В обсуждении моего ответа на вопрос возник один спорный момент.
Допустим имеем обобщенный класс и три метода в нем:
class SomeClass<T>
{
//не обобщенный метод
public void DoSomething(int x)
{
Console.WriteLine("True non generic method");
}
//не обобщенный метод с параметром обобщенного типа класса
public void DoSomething(T x)
{
Console.WriteLine("Indirectly generic method");
}
//явно обобщенный метод
public void DoSomething<U>(U x)
{
Console.WriteLine("True generic method");
}
}
Собственно вопрос - является ли не обобщенный метод, с параметром обобщенного типа класса, обобщенным методом?
Всё же, как вы догадались, ответ необобщённый (non-generic). Потому что есть определение, что такое обобщённый метод и всё.
Метод считается обобщённым, когда у него есть свой параметр типа. Если у него его нет, то это необобщённый метод.
У обобщённого класса метод может заимствовать параметр тип для возвращаемого значения или для типа параметра (не путайте тип параметра с параметром типа, хотя этот каламбур, наверняка, наводит путаницу), но это не сделает его обобщённым, если у него нету своего параметра типа.
И ваши исследования генерируемого IL совершенно не противоречат мои доводам. Но я бы всё равно не смешивал терминологию языка программирования и детали его реализации. Я не считаю это корректным.
Подкину тему для размышлений: иногда невиртуальные методы вызываются как виртуальные. Просто генерируется инструкция callvirt
в некоторых случаях для невиртуальных методов и всё. Можно было бы также спросить "Может их следует называть неявно виртуальные?" (Но тут скорей очевидно, что это просто делать реализации).
Но для начинающих (и не только) разработчиков — это, по крайней мере поначалу, странно. К примеру, все привычные члены Dictionary
необобщённые: Add(TKey, TValue)
, ContainsKey(TKey)
, TryGetValue(TKey, TValue)
, Remove(TKey)
и т.д.. И это многих удивляет, даже иногда тех, кто пользовался годами этим словарём. Тип обобщённый, но методы — нет. У List
дела обстоят интересно: у него только один обобщённый метод ConvertAll<TOutput>(Converter<T, TOutput>)
, остальные — нет.
В MSDN такие методы называются не обобщенными методами обобщенного класса, что ни чем не лучше моей формулировки в вопросе. В спецификации такой вариант тоже не рассматривается отдельно. Ок, раз ни где ни чего конкретно не написано спросим у самой CLR, в конце концов именно ей исполнять все что мы понаписали.
Итак, начнем с объявления класса
.class public auto ansi beforefieldinit ConsoleApplication.SomeClass`1<T>
Интересный момент: `1 - цифры после апострофа означают число параметров типа, но главная задача этой прибавки - расширение имени класса. Таким образом у нас может быть два класса с одинаковым именем и разным количеством обобщающих параметров включая не обобщенный класс без параметров.
Объявления методов (тело опускаю, т.к. не важно в данном случае):
Не обобщенный метод
.method public hidebysig
instance void DoSomething (
int32 x //тип указан явно
) cil managed
Явно обобщенный метод
.method public hidebysig
instance void DoSomething<U> (
!!U x //обратите внимание на два восклицательных знака
) cil managed
Два восклицательных знака сообщают JITу что конкретный тип нужно искать в обобщающих параметрах метода
Не обобщенный метод с параметром обобщенного типа класса
.method public hidebysig
instance void DoSomething (
!T x //тут только один восклицательный знак
) cil managed
Один восклицательных знака сообщают JITу что конкретный тип нужно искать в обобщающих параметрах класса.
Ок, уже что-то, теперь взглянем на то, как эти методы вызываются:
Не обобщенный метод
call instance void class ConsoleApplication.SomeClass`1<int32>::DoSomething(int32)
тип параметра указывается явно
Явно обобщенный метод
call instance void class ConsoleApplication.SomeClass`1<int32>::DoSomething<int32>(!!0)
тип параметра указывается ссылкой на параметр с индексом 0 в списке обобщающих параметров метода
Не обобщенный метод с параметром обобщенного типа класса
call instance void class ConsoleApplication.SomeClass`1<int32>::DoSomething(!0)
тип параметра указывается ссылкой на параметр с индексом 0 в списке обобщающих параметров класса
Получается, что в текущей реализации мы имеем два вида обобщенных методов - явные и неявные. В обоих случаях JITу потребуются дополнительные действия при компиляции данных методов для разрешения типов, т.к. в обоих случаях при вызове указана только ссылка на элемент списка обобщающих параметров.
Итого:
Есть два типа методов - обобщенные и не обобщенные.
Обобщенные методы могут быть обобщенными явно и неявно.
Приоритет при выборе перегруженного метода при прочих равных условиях:
В спецификации эту информацию найти можно, но только косвенно, прямых упоминаний нет, видимо понадеялись на логику читающих.
PS: Если есть другое объяснение, с удовольствием его прочитаю в вашем ответе.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Привет изучаю сокеты на c# и для практики есть такая идеяЕсть два простеньких приложения сервер и клиент
Ветки нужно перемещать ноды на уровень выше в материнские и ниже в дочерние
Есть 2 потока , которые рисуют 2 машинки на консоли и имитируют их движениеМашинка -Враг- спускается сверху , а игрок должен ее обойти