Предисловие: перейдите к редактированию, если хотите получить полное объяснение.Спойлер: Методы расширения - это хитрость компилятора, и на самом деле они имеют еще один аргумент, чем они выглядят, когда вы вызываете их .
Это в разрешении группы методов.По-видимому, компилятор C # не тратит время на выяснение того, имеет ли используемый вами метод перегрузки или нет;это просто всегда требует явного приведения.Извлечь:
Что такое группа методов в C #?
Вывод метода не работает с группой методов
Группа методов, котораявозвращается из reader.GetDoubleOrNull
сужается из-за того, что вы пытаетесь привести его к: GetDoubleOrNull
может ссылаться на любое количество перегруженных методов с этим именем.Вы должны явно привести его.
Интересно, что вы даже не можете назначить группу методов неявно типизированной переменной по той же причине:
var x = reader.GetDoubleOrNull;
не компилируется, потому что для этого требуетсяявное приведение.
Edit Я почти уверен, что путаница здесь связана с методами расширения:
Проверьте следующий тестовый класс:
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?>
, компилятор собирается "Я могу включить GetDoubleOrNull
в Func<IDataReader, string, double?>
, потому что у него есть два аргумента, но я не знаю, как превратить его в Func<string, double?>
"
Даже если вы называете его как экземплярметод IDataReader
с одним аргументом, это не : это просто статический метод с двумя аргументами, который C # заставил вас думать, что он является частью IDataReader
.