2012-03-07 3 views
13

У меня есть два метода расширения на 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, не было бы разрешения перегрузки, и он мог бы вывести параметр типа из подписи метода.

На самом деле запутанная часть заключается в том, как она работает при прохождении blah.

+3

Очень интересно. Явный листинг '' var x = reader.GetList ((Func ) Reader.GetDoubleOrNull) '' также работает. Resharper отмечает листинг как избыточный, но без компиляции. Джон Скит? –

+3

Есть ли способ вызвать Джона Скита (или, может быть, Эрика Липперта)? Скажи свое имя трижды или что-то в этом роде? – Chris

+1

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

ответ

0

GetDoubleOrNull возвращает двойной? GetList ожидает IDataReader и System.Func<string,int?>

Сообщение об ошибке является немного вводит в заблуждение

общественности двойник? blah (строка s)

var x = reader.GetList (blah);

blah является делегатом в этом звонке. В GetList (GetDoubleOrNull) это результат получения doubleOrNull.

Хороший вопрос. Поставьте ответ, помогая мне или нет.

+0

'' int'' должен быть опечаткой, и ее изменение на '' double'' все равно дает ошибку компилятора. –

+0

Яцек правильный. Виноват. Сожалею. – Moss

+1

Вы сказали: «В GetList (GetDoubleOrNull) это результат получения doubleOrNull», но это неправильно. В этом случае 'GetDoubleOrNull' не оценивается, он рассматривается как группа методов. – Chris

8

Предисловие: перейти к редактированию, если вы хотите получить полное объяснение. Спойлер: Методы расширения - это трюк компилятора, и на самом деле есть еще один аргумент, чем они выглядят, когда вы вызываете их.

Это решение группы методов. По-видимому, компилятор 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.

+0

Отличный ответ и исследования. Я хочу снова его повторить. ;-) – Chris

+3

Я не Джон Скит, но я делаю все, что могу: D – eouw0o83hf

+0

Спасибо за ваш ответ. К сожалению, по-прежнему я, похоже, не понимаю эту проблему. Первый вопрос, на который вы ссылаетесь, - это тот, о котором я знаю. Я прочитал второй, а также те, которые были опубликованы AakashM, и мне кажется, что все зависит от того, как разрешение перегрузки не учитывает типы возврата. Я это понимаю. Но как же проходит передача 'blah'? Нет ли в этом случае разрешения перегрузки? Если нет, почему бы и нет? Если да, то как это получается? – Moss

Смежные вопросы