簡體   English   中英

將擴展方法組轉換為具有泛型類型的委托

[英]Converting an extension method group to a delegate with a generic type

我在IDataReader上有兩個擴展方法,具有以下簽名:

internal static List<T> GetList<T>(this IDataReader reader, Func<string, T> del)

internal static double? GetDoubleOrNull(this IDataReader reader, string columnName)

GetDoubleOrNull沒有任何重載。

在其他地方,我能做到

Func<string, double?> del = reader.GetDoubleOrNull;

var x = reader.GetList(del);

要么

var x = reader.GetList<double?>(reader.GetDoubleOrNull);

或者只是傳入一個類似的實例方法

public double? blah(string s)

var x = reader.GetList(blah);

但我不能這樣做

var x = reader.GetList(reader.GetDoubleOrNull);

編譯器給出錯誤

cannot convert from 'method group' to 'System.Func<string,double?>'

我不明白這一點。 我認為,因為GetDoubleOrNull沒有重載,所以不會有重載GetDoubleOrNull ,它可以從方法簽名推斷出類型參數。

真正令人困惑的部分是它在傳遞blah時似乎如何工作。

前言:如果需要完整說明,請跳至編輯。 Spoiler: 擴展方法是一種編譯器技巧,實際上還有一個參數比它們調用它們時的樣子

它在方法組的分辨率中。 顯然C#編譯器沒有花時間弄清楚你使用的方法是否有重載; 它總是需要一個明確的演員。 查看:

C#中的方法組是什么?
方法推斷不適用於方法組

reader.GetDoubleOrNull返回的方法組由您嘗試將其GetDoubleOrNull為: GetDoubleOrNull可以引用具有該名稱的任意數量的重載方法。 你必須明確地施展它。

有趣的是,出於同樣的原因,您甚至無法將方法組分配給隱式類型變量:

var x = reader.GetDoubleOrNull;

無法編譯,因為它需要顯式轉換。

編輯我很確定這里的混淆與擴展方法有關:

查看以下測試類:

public static class Extensions
{
    public static List<T> GetList<T>(this IDataReader reader, Func<string, T> del)
    {
        throw new NotImplementedException();
    }

    public static double? GetDoubleOrNull(this IDataReader reader, string columnName)
    {
        throw new NotImplementedException();
    }

    public static double? blah(this string s)
    {
        throw new NotImplementedException();
    }
}

你可以成功打電話

var x = reader.GetList(Extensions.blah);

為什么會這樣 blah也是一種靜態擴展方法,因此,根據你的證據,看起來上面的行不應該編譯。 更復雜的是,讓我們添加這個方法:

public static List<T> GetList2<T>(this IDataReader reader, Func<IDataReader, string, T> del) 
{ 
    throw new NotImplementedException(); 
}

你現在可以打電話了

x = reader.GetList2(Extensions.GetDoubleOrNull);

它會正確編譯。 是什么賦予了?

答案如下:擴展方法實際上並沒有向對象添加方法。 它們真的是一個編譯器技巧,允許你編程,好像這些方法是你的類的一部分。 這里

在您的代碼中,您使用實例方法語法調用擴展方法。 但是,編譯器生成的中間語言(IL)會將您的代碼轉換為靜態方法的調用。 因此,封裝原則並未真正被違反。 實際上,擴展方法無法訪問它們正在擴展的類型中的私有變量。

所以,當你打電話的時候

var x = reader.GetDoubleOrNull("myColumnName");

實際上正在編譯和執行的內容基本上是這個(一個完全合法的調用,即使它是一個擴展方法):

var x = Extensions.GetDoubleOrNull(reader, "myColumnName");

因此,當你嘗試使用GetDoubleOrNull作為Func<string, double?>的arg Func<string, double?> ,編譯器將“我可以將GetDoubleOrNull轉換為Func<IDataReader, string, double?>因為它有兩個參數,但我不知道我不知道怎么把它變成Func<string, double?>

即使你把它稱為IDataReader的一個實例方法,只有一個arg,它也不是 :它只是一個帶有兩個args的靜態方法,C#編譯器已經欺騙你思考是IDataReader一部分。

GetDoubleOrNull返回一個double? GetList需要一個IDataReader和一個System.Func<string,int?>

錯誤消息有點誤導

公開雙? blah(字符串s)

var x = reader.GetList(blah);

blah是這次電話會議的代表。 在GetList(GetDoubleOrNull)中,它是get doubleOrNull的結果。

不錯的問題。 如果我幫助與否,請發布答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM