Читая книгу Джона Скита 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);