简体   繁体   中英

How does the C# compiler work with generics?

In C++, the template declarations need to be in a header file (unless you explicitly declare the template type), and I see understand why.

What I don't get is how the C# compiler can handle generics if it doesn't have the .cs file to examine. I doubt it examines the CIL as that would be a processor intensive operation. I know it is able to extract type information from the metadata, but if the code of the generic functions were encoded also, it would be a huge bloat to the executable.

So, again, how does the compiler work with generics?

I guess you're asking about how the C# compiler consumes generic types defined in a referenced assembly, rather than asking about how the C# compiler compiles a .cs file that defines a generic type (since you say "if it doesn't have the .cs file").

Generic types and members are encoded as generic in IL. The closed generic types and members are constructed by the jit compiler at run time. So the trivial answer to your question is "the C# compiler handles generic types by emitting IL that causes the jit compiler to construct them at run time."

C# compiler reads metadata about types from assemblies, no need to look at IL. You can write similar code using reflection to analyze generic types.

C# compiler also have no reason to look inside implementation of methods.

Please check What are the differences between Generics in C# and Java... and Templates in C++? and similar search results for reasons why C# does not need to know implementation of method (unlike C++) - all constraints in C# are known from class/method signature unlike in C++ templates where type just need to match names of methods used inside body.

Let me try to clear things up...

Generics are stored as IL including the parameters and constraints in the metadata. Generic types are types as well, which are converted to runtime types at runtime. This is the main difference from C++ where the template types don't exist, but only the derived types; in C# the generic types exist in the DLL, but the derived types do not (until they are created at run-time).

However, there are some things the compiler does do. If you have a List.Add(T) for example, the signature for that in the IL is exactly that. However, if you call it, it resolves the method using List.Add(Foo) as method. Eg in your IL it will show something like this (when loading a field):

ldfld class [mscorlib]System.List`1<Foo> Bar::variable

Notice that 'Foo' is here and not 'T'.

Also, if you put constraints on the T in your generics definition, they are checked compile-time against the metadata.

At this point I'd like to point out something entirely different but related. C# gains performance by lazy-generating types (in general). This is also very different from C++. You can see this in action if you experiment with static constructors and when they are called.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM