Компилятор C # завершается с ошибочной ошибкой при вызове универсального метода расширения с динамическим аргументом - PullRequest
2 голосов
/ 08 ноября 2019

Читая книгу Джона Скита C # В 4-м выпуске Depth я проводил некоторые тесты на ограничения динамического связывания, связанные с методами расширения. Как говорит Джон в этой главе, динамическое связывание не поддерживается для методов расширения в .NET, поэтому компилятор не позволяет нам передавать динамическое значение в качестве аргумента, вызывая соответствующую ошибку CS1973. Так для следующего кода:

//Provided this extension method
public static int GetFoo(this List<int> target, int value) => value * 10;

//And the following code at the call site
dynamic d = 1;
var items = new List<int> { 1, 2, 3 };
var result = items.GetFoo(d); //Error CS1973 as expected because
                              //we passed a dynamic argument

Сообщение об ошибке является простым:

List<int> не имеет применимого метода с именем GetFoo, но, похоже, имеет расширениеметод с этим именем. Методы расширения не могут быть динамически отправлены. Попробуйте привести динамические аргументы или вызвать метод расширения без синтаксиса метода расширения.

Не удивительно до сих пор. Но если мы немного изменим метод расширения, чтобы сделать его универсальным, чтобы принимать List<T> вместо List<int>, компилятор теперь вызывает другую ошибку CS1929.

//The generic version of 'GetFoo' seen above
public static int GetFooGeneric<T>(this List<T> target, int value) => value * 10;

//Unexpectedly, the following call raises error CS1929 (instead of CS1973)
var result = items.GetFooGeneric(d);

И сообщение об ошибке, на мой взгляд, вводит в заблуждение как бессмысленное:

List<int> не содержит определения для GetFooGeneric, а для лучшей перегрузки метода расширения Extensions.GetFooGeneric<T>(List<T>, int) требуется приемник типаList<T>.

Вводит в заблуждение, потому что скрывает отсутствие поддержки динамического связывания для методов расширения, и нет смысла иметь экземпляр типа List<T> в качестве получателя для вызоваметод расширения включен.

Кто-нибудь знает, что происходит за кулисами, что заставляет компилятор выдавать это вводящее в заблуждение сообщение об ошибке?


PS: В качестве примечания: если мы предоставим аргумент типа для того же универсального метода, компилятор снова выдаст соответствующую ошибку CS1973, как и ожидалось.

//By helping the compiler explicitly, it raises CS1973 appropriately
var result = items.GetFooGeneric<int>(d);

Ответы [ 2 ]

2 голосов
/ 13 ноября 2019

Уч. Это действительно плохо! Я не помню, была ли это моя ошибка или нет, но вы определенно правы, что это ужасное сообщение об ошибке.

Это возможно является результатом некоторых эвристических действий, которые мы ввелианализатор для решения ситуаций, когда вы на самом деле набираете код в редакторе, и нам нужно сделать вывод типа при неполном или неправильном вызове метода расширения, чтобы получить правильный IntelliSense;возможно, это плохо взаимодействует с динамическим аргументом? Но мне нужно было бы на самом деле взглянуть на код, чтобы освежить там свою память.

Если у меня будет время попозже сегодня, я посмотрю на источники Roslyn и выясню, узнаю ли я этот путь к коду.

Я знаю, что это не очень хороший ответ на ваш вопрос, но я не отлаживал этот путь кода по крайней мере с 2012 года, так что я вспоминаю эти варианты дизайна не так, как раньше. :)

0 голосов
/ 08 ноября 2019

Вы пишете: GetValueGeneric<T>(this List<T> target, int value) Обратите внимание, что вы пишете Значение

Вызов items.GetFooGeneric(d); приведет к CS1929, потому что ваша функция не существует.

Я попробовал items.GetValueGeneric(d); и это дает CS1973

...