Страницы

Поиск по вопросам

пятница, 29 ноября 2019 г.

Generic или не Generic

#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: Если есть другое объяснение, с удовольствием его прочитаю в вашем ответе.

Комментариев нет:

Отправить комментарий