Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pass a generic type to a generic method?

Tags:

c#

generics

Why can't I call SomeGenericMethod<SomeGenericType<>>?

class NotGeneric { }

class Generic<T> { }

class Program
{
    static void Main(string[] args)
    {
        PrintType(typeof(NotGeneric));
        PrintType(typeof(Generic<>));
        PrintType<NotGeneric>();
        PrintType<Generic<>>(); // compiler goes crazy here
    }

    static void PrintType<T>()
    {
        Console.WriteLine(typeof(T));
    }

    static void PrintType(Type t)
    {
        Console.WriteLine(t);
    }
}
like image 578
talles Avatar asked Apr 01 '16 13:04

talles


People also ask

Is it possible to inherit from a generic type?

An attribute cannot inherit from a generic class, nor can a generic class inherit from an attribute.

How do you pass a generic object in Java?

Generics Work Only with Reference Types: When we declare an instance of a generic type, the type argument passed to the type parameter must be a reference type. We cannot use primitive data types like int, char. Test<int> obj = new Test<int>(20);

How do you declare a generic method How do you invoke a generic method?

Generic MethodsAll generic method declarations have a type parameter section delimited by angle brackets (< and >) that precedes the method's return type ( < E > in the next example). Each type parameter section contains one or more type parameters separated by commas.

How does a generic method differ from a generic type?

From the point of view of reflection, the difference between a generic type and an ordinary type is that a generic type has associated with it a set of type parameters (if it is a generic type definition) or type arguments (if it is a constructed type). A generic method differs from an ordinary method in the same way.


2 Answers

Compiler needs specialized type to specialize the generic method and Generic<> is not specialized, it is generic. So, while Generic<> is a type, it is not specialized to be used for specialization of generic method.

like image 86
Riad Baghbanli Avatar answered Sep 28 '22 10:09

Riad Baghbanli


Why can't I call SomeGenericMethod<SomeGenericType<>>

The simplest answer is: because the language specification says so:

4.4 Constructed types

A generic type declaration, by itself, denotes an unbound generic type that is used as a “blueprint” to form many different types, by way of applying type arguments. The type arguments are written within angle brackets (< and >) immediately following the name of the generic type. A type that includes at least one type argument is called a constructed type. A constructed type can be used in most places in the language in which a type name can appear. An unbound generic type can only be used within a typeof-expression (§7.6.11).

4.4.3 Bound and unbound types

The term unbound type refers to a non-generic type or an unbound generic type. The term bound type refers to a non-generic type or a constructed type. An unbound type refers to the entity declared by a type declaration. An unbound generic type is not itself a type, and cannot be used as the type of a variable, argument or return value, or as a base type. The only construct in which an unbound generic type can be referenced is the typeof expression (§7.6.11).

Why does the C# spec says so? Because the CLI spec dictates that as well:

II.9.4 Instantiating generic types

...

The CLI does not support partial instantiation of generic types. And generic types shall not appear uninstantiated anywhere in metadata signature blobs.

Ok, now let's stop with the legalese. The actual answer to your question is:

When you call SomeMethod<SomeType>() for the first time, the CLR will invoke the JIT compiler, which will read SomeMethod<T>, substitute T, and create new executable code which represents SomeMethod<SomeType>.

When you call SomeMethod<SomeOtherType>(), the process needs to be repeated, brand new code will be generated for SomeMethod<SomeOtherType>.

You can't just create valid code for an unbound generic type like Generic<>. In the general case, the JIT can't know what code representation to generate without knowing T.

  • If T is a string and your method declares a local variable of type T, the JIT will allocate stack space or use a register with the size of a native pointer.
  • If T is a Guid, the JIT will have to allocate stack space for a fixed 128 bits value. It can't generate code if it doesn't know what T is going to be.

Therefore, in general, you can't generate executable code for an unbound type. Why you arguably could do just that for the snippet you provided, this would require special-casing, and your calling code would stop working if you added a T local in the PrintType method. As generics have to be reusable across assemblies, calling code cannot assume anything about the called method.

like image 45
Lucas Trzesniewski Avatar answered Sep 28 '22 09:09

Lucas Trzesniewski