Why does the C # compiler allow use when using an interface, but it cannot determine the type when I use a class that implements the same interface?
Good question. Consider the following:
public interface I {} public class D {}
Let me break your question into three questions.
Why is casting directly from T to D forbidden?
Suppose this was legal. Then EM<D>(new D()) will work fine; we would put T on D and itβs actually D , so no problem.
Now suppose we create a completely different assembly with:
class C { public static explicit operator D(C c) { whatever } }
And you call EM<C>(new C()) in this assembly. What do you reasonably expect? You have an object of type C , it is added to D , and there is an explicit conversion operator from C to D Most people reasonably expected the explicit conversion operator to be called.
But how should the compiler really realize when compiling the body of M that someone in the future can create a class C in a completely different assembly? The compiler cannot fix the call to the conversion operator when compiling M So, we have three options:
- Make cast statements sometimes use explicit conversion operators, and sometimes not, depending on whether you are in general or not.
- Make literal statements run the compiler again at run time to look for explicit conversion statements that could be added to different assemblies after the source code has been compiled.
- Disallow listing first.
In short, our choices are: (1) make generics inconsistent, (2) make generics slow and unpredictable, or (3) inhibit a function that already works against typicality. This is a simple choice; we have chosen (3).
If you want (2), you can get it in C # 4; dynamic starts the compiler again at runtime and finds out if there is an explicit conversion statement.
Why is an indirect transfer from T to D through a legal entity?
Because now no user transformation can be relevant; there is never a custom conversion from an object to something.
Why is the indirect transfer from T to D through I legal?
Because now no user transformation can be relevant; never will the user determine the conversion from the interface to anything.
Bonus question:
But D doesn't even implement I ! What's up with that?
Derived class D can:
class F : D, I {} ... EM<D>(new F());
Now T can be added to I because it can implement I , and I can be added to D because it can be F
If D were sealed , then it would not be legal to drop I to D , because then there could be no derived type F