Reputation: 672
In Java, this code doesn't work:
public <T> void foo() { print(T.class); } // compile time error
Beacuse the generic type T
is erased at runtime. To use T
, I must use it as an argument, which will push String.class
into stack
public <T> void foo(Class<T> T) { print(T); }
public void bar() { foo(String.class); }
But in C#, I can get type argument at runtime:
public void Foo<T>() { print(typeof(T)); }
How does it work? Does the compiler (or vm) automatically translate void Foo<T>()
to void Foo(Type T)
?
update:
I disassembled the bytecode and got something like:
ldtoken !!T
call System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)
Since ldtoken
is an instruction which "Convert metadata token to its runtime representation", it's clear that the runtime type of T
is stored as metadata.
I guess each method has it's own "metadata table" (or something like that), so calling Foo<string>()
and Foo<object>()
will generate two "method handle" and two "metadata table", but share the same machine code. Is it?
Upvotes: 5
Views: 225
Reputation: 101681
Does the compiler (or vm) automatically translate void Foo() to void Foo(Type T)?
No it doesn't. The body for generic methods is generated at runtime, on the fly. So, for example, when you supply T
as int
, this method is generated:
public void Foo<int>() { print(typeof(int)); }
This happens every time you pass a different type. But if you use the same type again the CLR will cache the previously generated method and execute it, instead of generating a new one.
Upvotes: 5
Reputation: 2383
In .NET, generics are not erased. The CLR implements generics all the way down to the byte code.
Upvotes: 0