[英]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#編譯器沒有花時間弄清楚你使用的方法是否有重載; 它總是需要一個明確的演員。 查看:
從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.