Не удается вызвать методы расширения с динамическими параметрами и дженериками

Мне любопытно узнать, сталкивался ли кто-нибудь еще с такой же проблемой... Я использую Dapper как ORM для проекта и создавал некоторые из моих собственных методов расширения для интерфейса IDbConnection, чтобы упростить код, где я столкнулся (как я обнаружил) с загадочной ошибкой.

Я пройду через процесс, через который я прошел.

Во-первых, я добавил метод расширения в свой проект в статическом классе с именем DbExtensionsследующим образом:

using System.Collections.Generic;
using System.Data;
using System.Linq;

public static class DbExtensions
{
    public static T Scalar<T>(
        this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
    {
        var ret = cnn.Query<T>(sql, param as object, transaction, buffered, commandTimeout, commandType).First();
        return ret;
    }
}

Это создает ошибку компиляции со следующим описанием:

'System.Data.IDbConnection ' не имеет применимого метода с именем 'Query', но, по-видимому, имеет метод расширения с таким именем. Методы расширения не могут быть отправлены динамически. Рассмотрите возможность приведения динамических аргументов или вызова метода расширения без синтаксиса метода расширения.

Это нормально, и ошибка на самом деле довольно полезна, поскольку она даже говорит мне, как ее исправить. Затем я пытаюсь:

using System.Collections.Generic;
using System.Data;
using System.Linq;

public static class DbExtensions
{
    public static T Scalar<T>(
        this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
    {
        var ret = SqlMapper.Query<T>(cnn, sql, param, transaction, buffered, commandTimeout, commandType).First();
        return ret;
    }
}

, и он компилируется правильно. Хотя происходит что-то странное. В Visual Studio, если я возьму возвращаемое значение SqlMapper.Query, которое должнобыть IEnumerable, и попытаюсь с ним работать , Visual Studio не дает мне никаких свойств IntelliSense, кроме тех, которые унаследованы через object.

Думая, что я просто делаю что-то, что intellisense не может понять, я продолжаю свой веселый путь... пока я не пытаюсь запустить код.

Когда я пытаюсь запустить его, он срабатывает там, где я вызываю .First()со следующей ошибкой:

'System.Collections.Generic.List' действительно не содержит определения для 'First'

Теперь ЭТА ошибка, я подумал, что это интересно... Немного помотав головой, я понял, что первый аргумент жаловался на динамическую типизацию...

Я полагаю, что это ошибка возникает из-за того, что компилятор не может построить универсальный шаблон, так как он не знает, что запрос возвращает IEnumerable, поскольку он выполняется в DLR? Хотелось бы услышать объяснение от знающего человека. По сути, я нашел два способа исправить это:

  • Привести параметр dynamicк объекту
  • Привести возвращаемое значение к IEnumerable

using System.Collections.Generic;
using System.Data;
using System.Linq;

public static class DbExtensions
{
    public static T Scalar<T>(
        this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
    {
        var ret = SqlMapper.Query<T>(cnn, sql, param as object, transaction, buffered, commandTimeout, commandType).First();
        return ret;
    }
}

using System.Collections.Generic;
using System.Data;
using System.Linq;

public static class DbExtensions
{
    public static T Scalar2<T>(
        this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
    {
        var ret = ((IEnumerable<T>)SqlMapper.Query<T>(cnn, sql, param, transaction, commandTimeout, commandType)).First();
        return ret;
    }
}

В РЕЗЮМЕ :

Я новичок в работе с qwerks DLR, и, кажется, есть некоторые предостережения, которые следует иметь в виду, возясь с динамическими + универсальными...?

Я знаю, что это не вопрос как таковой, но когда я на самом деле начал писать это, я не знал, что происходит, и я понял это в процессе! Я подумал, что это может помочь кому-то еще с похожими проблемами...

11
задан Leland Richardson 13 June 2012 в 02:51
поделиться