In the discussion of my answer to the question, one controversial point arose.

Suppose we have a generalized class and three methods in it:

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"); } } 

Actually the question is - is a non-generic method, with a parameter of a generalized class type, a generic method?

    2 answers 2

    Yet, you guessed it, the answer is non-generic. Because there is a definition of what a generic method is and that's it.

    The method is considered generalized when it has its own type parameter . If he does not have it, then this is a non-generic method.

    A generic type method can borrow a type parameter for the return value and / or parameter type (do not confuse the parameter type with the type parameter , although this pun probably confuses), but this does not make it generalized if the method does not have its own type parameter .

    And your research generated IL does not contradict my arguments. But I still would not confuse the terminology of a programming language and the details of its implementation. I do not think this is correct.


    Throwing a topic for reflection: sometimes non-virtual methods are invoked as virtual ones . The callvirt instruction is generated in some cases for non-virtual methods and that's it. One might also ask, "Should they be called implicitly virtual?" ( But then it’s rather obvious that it’s just doing implementations ).


    Embarrassment for developers

    But for beginners (and not only) developers - it is, at least initially, strange. For example, all the usual members of the Dictionary generalized: Add(TKey, TValue) , ContainsKey(TKey) , TryGetValue(TKey, TValue) , Remove(TKey) , etc. And this is surprising to many, even sometimes those who have used it for years this dictionary. The type is generalized, but the methods are not. List of things is interesting: it has only one generalized method ConvertAll<TOutput>(Converter<T, TOutput>) , the others are not.

    • public void DoSomething (T x) {Console.WriteLine ("Indirectly generic method"); } and // an explicitly generalized method public void DoSomething <U> (U x) {Console.WriteLine ("True generic method"); } equivalent, just the first "implicitly generalized." - CSharpUser
    • @CSharpUser I do not understand your comment. Do you want to challenge or prove me? - Vadim Ovchinnikov

    In MSDN, such methods are called non-generic methods of the generalized class, which is no better than my wording in the question. In the specification, this option is also not considered separately. Ok, since no matter where it’s written specifically, we’ll ask the CLR itself, in the end, it’s up to her to do everything we’ve written.

    So let's start with the class declaration.

     .class public auto ansi beforefieldinit ConsoleApplication.SomeClass`1<T> 

    An interesting point: `1 - the numbers after the apostrophe mean the number of type parameters, but the main task of this increase is to expand the class name. Thus, we can have two classes with the same name and a different number of generic parameters, including a non-generic class without parameters.

    Method declarations (body omitted, since it does not matter in this case):

    Not a generic method

     .method public hidebysig instance void DoSomething ( int32 x //тип указан явно ) cil managed 

    Explicitly generalized method

     .method public hidebysig instance void DoSomething<U> ( !!U x //обратите внимание на два восклицательных знака ) cil managed 

    Two exclamation marks tell JIT what specific type to look for in the generalizing parameters of the method.

    Non-generic method with a generic class type parameter

     .method public hidebysig instance void DoSomething ( !T x //тут только один восклицательный знак ) cil managed 

    One exclamation mark tells JIT that a specific type should be searched for in the class generalizing parameters.

    Ok, already something, now let's take a look at how these methods are invoked:

    Not a generic method

     call instance void class ConsoleApplication.SomeClass`1<int32>::DoSomething(int32) 

    the type of the parameter is explicit

    Explicitly generalized method

     call instance void class ConsoleApplication.SomeClass`1<int32>::DoSomething<int32>(!!0) 

    the type of the parameter is indicated by a reference to the parameter with index 0 in the list of generalizing method parameters

    Non-generic method with a generic class type parameter

     call instance void class ConsoleApplication.SomeClass`1<int32>::DoSomething(!0) 

    the type of the parameter is indicated by a reference to the parameter with index 0 in the list of generalizing parameters of the class

    It turns out that in the current implementation we have two types of generalized methods - explicit and implicit. In both cases, the JIT will need additional steps when compiling these methods to resolve types, since in both cases, the call indicates only a reference to the element of the list of generalizing parameters.

    Total for a specific implementation of the compiler / JIT / VM:

    1. There are two types of methods - generalized and not generalized .

    2. Generalized methods can be generalized explicitly and implicitly .

    3. Priority when choosing an overloaded method with other things being equal:

      • not generalized
      • implicitly generalized
      • clearly generalized

    This information can be found in the specification, but only indirectly, there are no direct references, apparently hoping for the logic of the readers.


    PS: If there is another explanation, I will read it with pleasure in your answer.

    • 2
      "In both cases, the CLR will require additional actions when calling these methods to resolve types" - no, the CLR is not an interpreter. In fact, there is indicated not a "link to the list of generalizing parameters", but to a specific methodDesc with specific types. When compiling the calling method, the JIT will climb into MT, extract the address from the JIT specific generic (specific, for value type, or common for all reference) from there and insert the call <address> into the place of the call. Those. There is one (quick) search for an implementation for a specific type at the time of a JIT. In the actual call, there are no losses or additional gestures. - PashaPash
    • 3
      I mean, now your answer seems to be hinting that generics are creating performance problems. although they solve them just :) - PashaPash
    • @PashaPash heavy artillery pulled up =) and wrote to find out all controversial points =) thanks - rdorn