UPDATE: This isn’t about getting it to compile. The question is, why does the C# compiler allow the cast when using an interface, but it can’t figure out the type when I use a class that implements the same interface.
I am getting the following error:
Cannot convert type 'Amber.BLL.iWeb.Session.AppSession' to 'TService'
Here is the code:
public override TService GetService<TService>()
{
if ( typeof( TService ) == typeof( IAppSession ) )
{
AppSession session = new AppSession();
return (TService) session;
}
throw new Exception( String.Format(
"iWebFactoryProvider cannot create services of type '{0}'.",
typeof( TService ).Name ) );
}
As it so happens, the AppSession class implements the IAppSession interface. If I change the line of code that instantiates AppSession to use the interface, like this:
IAppSession session = new AppSession();
suddenly everything compiles fine. I also note that it compiles fine if I do this:
AppSession session = new AppSession();
return (TService) (IAppSession) session;
In case it matters, the GetService() is overriding a method whose signature is declared like this:
public virtual TService GetService<TService>() where TService : class
In short, I can’t figure out what the rules should be here so I can know how to avoid this situation in the future. Why was the compiler happy to cast the interface, but not happy to cast the interface’s implementing class?
I note that this question is asking about a similar issue, but the answer isn’t detailed enough for me to understand how it applies to my situation.
Good question. Consider the following:
Let’s break your question up into three questions.
Suppose it were legal. Then
E.M<D>(new D())would work just fine; we’d cast theTtoDand in fact it is aD, so no problem.Now suppose we create an entirely different assembly with:
And you call
E.M<C>(new C())in that assembly.. What do you reasonably expect to happen? You have an object of typeC, it is being cast toD, and there is an explicit conversion operator right there fromCtoD. Most people would reasonably expect that the explicit conversion operator would be called.But how on earth is the compiler supposed to realize when compiling the body of
Mthat someone in the future might create a classCin a completely different assembly? The compiler has no way to emit the call to the conversion operator when compilingM. So we have three choices:In short, our choices are (1) make generics inconsistent, (2) make generics slow and unpredictable, or (3) disallow a feature that is already working against genericity. This is an easy choice to make; we chose (3).
If you want (2), you can have it in C# 4;
dynamicstarts the compiler again at runtime and works out whether there is an explicit conversion operator.Because now no user-defined conversion can be relevant; there is never a user-defined conversion from object to anything.
Because now no user-defined conversion can be relevant; there is never a user-defined conversion from an interface to anything.
Bonus question:
A derived class of
Dmight:Now
tcan be cast toIbecause it might implementI, andIcan be cast toDbecause it might beF.If
Dweresealedthen it would not be legal to cast fromItoDbecause then there could not possibly be a derivedFtype.