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