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