首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不能使用动态参数和泛型调用扩展方法

不能使用动态参数和泛型调用扩展方法
EN

Stack Overflow用户
提问于 2012-06-13 02:44:38
回答 1查看 5.7K关注 0票数 11

我很好奇有没有人遇到过同样的问题.我在ORM上使用Dapper作为一个项目,并在IDbConnection接口之外创建了一些自己的扩展方法,以简化代码,在那里我遇到了(我发现的)令人费解的错误。

我将走过我所经历的过程。

首先,我在一个名为DbExtensions 的静态类中向项目添加了一个扩展方法,如下所示:

代码语言:javascript
复制
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.

这很好,而且这个错误实际上是非常有用的,因为它甚至告诉我如何修复它。于是我试着:

代码语言:javascript
复制
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

  • Cast

  • dynamic参数转换为IEnumerable<T>

返回的值。

代码语言:javascript
复制
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;
    }
}

代码语言:javascript
复制
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,在处理动态+泛型时,似乎需要记住一些警告.?

我知道这本身并不是一个问题,但当我真正开始写这篇文章时,我不知道发生了什么,我在这个过程中发现了它!我想这可能会帮助别人解决类似的问题.

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-06-13 14:51:01

按照建议,我会试着用实际的答案回答我的问题.(现在已经8个小时了)

我对这个问题的理解是:

正如在

  • 中所描述的,动态类型没有可用的扩展方法,但是扩展方法可以正常使用(作为实例方法),就像它们没有this关键字.

一样

例如:

代码语言:javascript
复制
dynamic list = someListObject;

var item = list.First(); //this will not compile

var item = Enumerable.First(list);  //this will compile

正如considered在this answer中指出的那样,这一切都是由设计完成的,也是DLR实现的一部分--如果任何调用都有动态参数,那么返回类型就会被认为是动态的。

  • 由于类似的原因,在扩展方法中使用动态变量有点不可靠.

代码语言:javascript
复制
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() 

要使上面的示例工作,您可以执行以下操作之一:

代码语言:javascript
复制
//cast dynamic as object
var returnedValue = x.ExtensionMethod(y as object).First(); 
//cast returned object
var returnedValue = ((IEnumerable<KnownType>)x.ExtensionMethod(y)).First(); 
票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11007573

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档