Мне любопытно узнать, столкнулся ли кто-то еще с этой проблемой ... Я использую 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' has no applicable method named 'Query' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.
Это хорошо, и ошибка на самом деле весьма полезна, поскольку она даже подсказывает, как ее исправить. Поэтому я затем попробую:
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<T>
, которое должно быть IEnumerable<T>
, и я пытаюсь работать с ним, Visual Studio не дает мне никаких свойств intellisense, кроме тех, которые унаследованы через object
.
Думаю, что я просто делаю то, что intellisense недостаточно умен, чтобы понять, я продолжаю свой веселый путь ... пока я на самом деле не попытаюсь запустить код.
Когда я пытаюсь запустить его, он срабатывает там, где я звоню .First()
со следующей ошибкой:
'System.Collections.Generic.List<MyNameSpace.MyClass>' does not contain a definition for 'First'
Теперь эта ошибка, я думал, было интересно ... После того, как стучал головой для в то время как я понял, что первый аргумент жаловался на динамическую типизацию ...
Я предполагаю, что эта ошибка возникает из-за того, что компилятор не может построить общий шаблон, поскольку он не знает, что Query возвращает IEnumerable<T>
, поскольку он выполняется в DLR? Я хотел бы услышать, как кто-то объяснил это, кто был осведомлен. Я по существу нашел два способа исправить:
- закиньте
dynamic
Param кobject
- Cast возвращенное значение в
IEnumerable<T>
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, и, похоже, есть некоторые предостережения, которые следует учитывать при взаимодействии с динамическими + Generics ...?
Я знаю, что это не вопрос, но когда я начал писать это, я не знал, что происходит, и я понял это в этом процессе! Я думал, что это может помочь кому-то еще с подобными проблемами, хотя ...
Возможный дубликат [Метод расширения и динамический объект в C#] (http://stackoverflow.com/questions/5311465/extens ion-method-and-dynamic-object-in-c-sharp) –
Это потрясающе, но обратите внимание, что для ответов на собственные вопросы соглашение идеально подходит для отправки вопросов и ответов отдельно. – McGarnagle
@dbaseman Спасибо. Я написал отдельный ответ, но, по-видимому, у меня недостаточно очков для «ответа на себя» до тех пор, пока не истечет 8 часов: P –