無法使用動態參數和泛型調用擴展方法

c# dapper dynamic extension-methods generics

我很想知道是否有其他人遇到過同樣的問題...我正在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 Studio中,如果我獲取SqlMapper.Query<T>的返回值,它應該IEnumerable<T> ,並且我嘗試對它進行操作,Visual Studio除了通過object繼承的屬性外,沒有給出智能感知屬性。

以為我只是在做一些智能感知不夠聰明的事情,我繼續我的快樂方式......直到我真的嘗試運行代碼。

當我嘗試運行它時,它會在我調用.First()時出現以下錯誤:

'System.Collections.Generic.List<MyNameSpace.MyClass>' does not contain a definition for 'First'

現在這個錯誤,我覺得很有意思......在敲了一下頭之後,我意識到第一個論點是抱怨動態打字......

我想這個錯誤正在發生,因為編譯器無法構建通用模板,因為它不知道Query正在返回IEnumerable<T>因為它正在DLR中執行?我很想听到有人解釋這個知識淵博的人。我基本上找到了兩種方法來解決它:

  • dynamic參數轉換為object
  • 將返回的值轉換為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的qwerks,在搞亂動態+泛型時,似乎需要記住一些注意事項......?

我知道這不是一個問題本身,但當我真正開始寫這篇文章時,我不知道發生了什麼,我在這個過程中想出來了!我認為它可能會幫助其他有類似問題的人...

一般承認的答案

正如所建議的那樣,我會嘗試在實際答案中回答我的問題......(現在已經8小時了)

我對這個問題的理解是這樣的:

  • 引用的問題中所述,動態類型沒有可用的擴展方法,但擴展方法可以正常使用(作為實例方法),就像它們沒有this關鍵字一樣...

例如:

dynamic list = someListObject;

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

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

正如Jon Skeet在本回答中指出的那樣, 完全是設計和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(); 


許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因