我很好奇有没有人遇到过同样的问题.我在ORM上使用Dapper作为一个项目,并在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中,如果我取SqlMapper.Query<T>的返回值(应该是IEnumerable<T> ),并尝试对其进行操作,Visual将不给我任何intellisense属性,只有那些通过object继承的属性。
我认为我只是在做一些智能感知不够聪明的事情,我继续我的快乐之路.直到我真的试着运行代码。
当我尝试运行它时,它会跳到我调用.First()的位置,其中包含以下错误:
'System.Collections.Generic.List<MyNameSpace.MyClass>' does not contain a definition for 'First'
这个错误,我觉得很有趣.敲了一会儿头后,我意识到第一个论点是抱怨动态打字.
我认为发生此错误是因为编译器无法构建通用模板,因为它不知道查询是在DLR中执行时返回IEnumerable<T>的?我很想听一个知识渊博的人解释这一点。我基本上找到了两种方法来解决这个问题:
object
dynamic参数转换为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;
}
}综述:
我不熟悉DLR的qwerk,在处理动态+泛型时,似乎需要记住一些警告.?
我知道这本身并不是一个问题,但当我真正开始写这篇文章时,我不知道发生了什么,我在这个过程中发现了它!我想这可能会帮助别人解决类似的问题.
发布于 2012-06-13 14:51:01
按照建议,我会试着用实际的答案回答我的问题.(现在已经8个小时了)
我对这个问题的理解是:
正如在
this关键字.一样
例如:
dynamic list = someListObject;
var item = list.First(); //this will not compile
var item = Enumerable.First(list); //this will compile正如considered在this answer中指出的那样,这一切都是由设计完成的,也是DLR实现的一部分--如果任何调用都有动态参数,那么返回类型就会被认为是动态的。
public static Enumerable<T> ExtensionMethod(this ExtendedObject p1, dynamic p2) {
//Do Stuff
}
dynamic y = something;
var x = new ExtendedObject();
//this works
var returnedEnumerable = x.ExtensionMethod(y);
//this doesn't work
var returnedValue = x.ExtensionMethod(y).SomeEnumerableExtensionMethodLikeFirst() 要使上面的示例工作,您可以执行以下操作之一:
//cast dynamic as object
var returnedValue = x.ExtensionMethod(y as object).First();
//cast returned object
var returnedValue = ((IEnumerable<KnownType>)x.ExtensionMethod(y)).First(); https://stackoverflow.com/questions/11007573
复制相似问题