Предисловие: перейти к редактированию, если вы хотите получить полное объяснение. Спойлер: Методы расширения - это трюк компилятора, и на самом деле есть еще один аргумент, чем они выглядят, когда вы вызываете их.
Это решение группы методов. По-видимому, компилятор C# не находит времени, чтобы выяснить, имеет ли метод, который вы используете, перегрузки или нет; он просто требует явного приведения. Проверьте:
What is a method group in C#?
Method Inference does not work with method group
Метод группа, которая возвращается из 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);
и он будет компилировать правильно. Что дает?
Вот ответ: Методы расширения не фактически добавьте методы в свои объекты. Они действительно трюк компилятора, который позволяет вам программировать так, как если бы эти методы были частью ваших классов. Из here:
В своем коде вы вызываете метод расширения с помощью метода экземпляра синтаксиса. Однако промежуточный язык (IL), сгенерированный компилятором , переводит ваш код в вызов статического метода. Таким образом, принцип инкапсуляции не является нарушением . Фактически, методы расширения не могут получить доступ к приватным переменным по типу, который они распространяют.
Так что, когда вы звоните
var x = reader.GetDoubleOrNull("myColumnName");
что на самом деле компилируется и выполняется, по существу, это (совершенно законный вызов, даже если это метод расширения):
var x = Extensions.GetDoubleOrNull(reader, "myColumnName");
Так , когда вы пытаетесь использовать GetDoubleOrNull
в качестве аргумента для Func<string, double?>
, компилятор собирается «Я могу превратить GetDoubleOrNull
в Func<IDataReader, string, double?>
, потому что он имеет два аргумента, но я не k Теперь, как превратить его в Func<string, double?>
"
Даже если вы вызываете его, как будто это метод экземпляра IDataReader
с одним аргом, не: это просто статический метод с двумя аргументами, что C# компилятор обманул вас, думая, что это часть IDataReader
.
Очень интересно. Явный листинг '' var x = reader.GetList ((Func) Reader.GetDoubleOrNull) '' также работает. Resharper отмечает листинг как избыточный, но без компиляции. Джон Скит? –
Есть ли способ вызвать Джона Скита (или, может быть, Эрика Липперта)? Скажи свое имя трижды или что-то в этом роде? – Chris
related: http://stackoverflow.com/questions/7745852/method-inference-does-not-work-with-method-group и http://stackoverflow.com/questions/2057146/compiler-ambiguous-invocation-error -anonymous-method-and-method-group-with-fun – AakashM