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.
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?
Good question. Consider the following:
public interface I {}
public class D {} // Note that D does not even implement I!
public class E
{
public static M<T>(T t)
{
D d1 = (D)t; // Illegal
D d2 = (D)(object)t; // Legal
D d3 = (D)(I)t; // Legal
}
}
Let's break your question up into three questions.
Why is the cast directly from T to D illegal?
Suppose it were legal. Then E.M<D>(new D()) would work just fine; we'd cast the T to D and in fact it is a D, so no problem.
Now suppose we create an entirely different assembly with:
class C
{
public static explicit operator D(C c) { whatever }
}
And you call E.M<C>(new C()) in that assembly.. What do you reasonably expect to happen? You have an object of type C, it is being cast to D, and there is an explicit conversion operator right there from C to D. 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 M that someone in the future might create a class C in a completely different assembly? The compiler has no way to emit the call to the conversion operator when compiling M. So we have three choices:
Make cast operators sometimes use explicit conversion operators and sometimes not, depending on whether you're in a generic or not.
Make cast operators start the compiler again at runtime to look for explicit conversion operators that might have been added in different assemblies after the original code was compiled.
Disallow the cast in the first place.
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; dynamic starts the compiler again at runtime and works out whether there is an explicit conversion operator.
Why is the cast indirectly from T to D via object legal?
Because now no user-defined conversion can be relevant; there is never a user-defined conversion from object to anything.
Why is the cast indirectly from T to D via I legal?
Because now no user-defined conversion can be relevant; there is never a user-defined conversion from an interface to anything.
Bonus question:
But D does not even implement I! What's up with that?
A derived class of D might:
class F : D, I {}
...
E.M<D>(new F());
Now t can be cast to I because it might implement I, and I can be cast to D because it might be F.
If D were sealed then it would not be legal to cast from I to D because then there could not possibly be a derived F type.
Have you tried adding a constraint for IAppSession?
public virtual TService GetService<TService>() where TService : IAppSession, class
That linked question is exactly the same issue. The compiler doesn't know that TService can be an AppSession.
You can convert the object by using (TService)(Object)instance or use constraints on the generic parameter.
The reason why the compiler is happy about the cast, is simply that he doesn't know what is behind the instance of a interface so the cast may succeed. When casting from class to generic type T he doesn't know if the cast is valid and throws a error at compile time. Of course he could do this also after compile but there is a good reason for this, imagine...
return (TService)myinstance;
is exchanged by:
return (CustomService)myinstance;
and the myinstance variable is not compatible with the type CustomService.
But a cast from a interface to TService may succeed, or from Object to TService.
Related
static IEnumerable<U> DoSomething<T, U>(IEnumerable<T> a)
where T : U
{
// Works, compiler can compile-time statically cast
// T as U.
T testA = default(T);
U testB = testA;
// And the following works, though:
IEnumerable<string> test2A = null;
IEnumerable<object> test2B = test2A;
// Doesn’t work. Compiler cannot compile-time statically
// cast IEnumerable<T> to IEnumerable<U> even though it is
// out and T is U.
return a;
}
I have code where being able to perform this type of implicit cast would save me writing a lot of boilerplate interface implementation code.
This seems to be the sort of thing which covariance was supposed to help with.
But I always get this error on the return a; line above:
error CS0266: Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<T>' to 'System.Collections.Generic.IEnumerable<U>'. An explicit conversion exists (are you missing a cast?)
Why is this this way and is there a way to work around this without doing something like return from o in a select o;?
When messing around with my minimal repro and reading similar, but unrelated, question about interface casting, I realized that the following compiles:
static IEnumerable<U> DoSomethingElse<T, U>(IEnumerable<T> a)
where T : class, U
{
// Works! Ridik!
return a;
}
And also that the following fails with the same error message:
static void Blah()
{
// Fails for I bet the same reason that DoSomething{T, U} fails:
IEnumerable<int> a = null;
IEnumerable<object> b = a;
}
error CS0266: Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<int>' to 'System.Collections.Generic.IEnumerable<object>'. An explicit conversion exists (are you missing a cast?)
So this seems to be related to how .net restricts certain types of assignments to reference types because boxing in these situations would either be the wrong thing (e.g., you might assume reference types and actually be working on a copy of a value type) or very hard/impossible to implement in the runtime (given an IEnumerable<int> you’d have to implement a wrapping adapting class. OK, so that sounds like something .net can’t/shouldn’t try to do for you at runtime). I think of it as a situation where .net allows pointer-style polymorphism which, by its very nature, is incompatible with the concept of value types.
So, for my case, I don’t need to support value types in my API here and adding the class constraint makes everything magical!
(Trying to find a title that sums up a problem can be a very daunting task!)
I have the following classes with some overloaded methods that produce a call ambiguity compiler error:
public class MyClass
{
public static void OverloadedMethod(MyClass l) { }
public static void OverloadedMethod(MyCastableClass l) { }
//Try commenting this out separately from the next implicit operator.
//Comment out the resulting offending casts in Test() as well.
public static implicit operator MyCastableClass(MyClass l)
{
return new MyCastableClass();
}
//Try commenting this out separately from the previous implicit operator.
//Comment out the resulting offending casts in Test() as well.
public static implicit operator MyClass(MyCastableClass l)
{
return new MyClass();
}
static void Test()
{
MyDerivedClass derived = new MyDerivedClass();
MyClass class1 = new MyClass();
MyClass class2 = new MyDerivedClass();
MyClass class3 = new MyCastableClass();
MyCastableClass castableClass1 = new MyCastableClass();
MyCastableClass castableClass2 = new MyClass();
MyCastableClass castableClass3 = new MyDerivedClass();
OverloadedMethod(derived); //Ambiguous call between OverloadedMethod(MyClass l) and OverloadedMethod(MyCastableClass l)
OverloadedMethod(class1);
OverloadedMethod(class2);
OverloadedMethod(class3);
OverloadedMethod(castableClass1);
OverloadedMethod(castableClass2);
OverloadedMethod(castableClass3);
}
public class MyDerivedClass : MyClass { }
public class MyCastableClass { }
There are two very interesting things to note:
Commenting out any of the implicit operator methods removes the ambiguity.
Trying to rename the first method overload in VS will rename the first four calls in the Test() method!
This naturally poses two questions:
What it the logic behind the compiler error (i.e. how did the compiler arrive to an ambiguity)?
Is there anything wrong with this design? Intuitively there should be no ambiguity and the offending call should be resolved in the first method overload (OverloadedMethod(MyClass l, MyClass r)) as MyDerivedClass is more closely related to MyClass rather than the castable but otherwise irrelevant MyCastableClass. Furthermore VS refactoring seems to agree with this intuition.
EDIT:
After playing around with VS refactoring, I saw that VS matches the offending method call with the first overload that is defined in code whichever that is. So if we interchange the two overloads VS matches the offending call to the one with the MyCastableClass parameter. The questions are still valid though.
What it the logic behind the compiler error (i.e. how did the compiler arrive to an ambiguity)?
First we must determine what methods are in the method group. Clearly there are two methods in the method group.
Second, we must determine which of those two methods are applicable. That is, every argument is convertible implicitly to the corresponding parameter type. Clearly both methods are applicable.
Third, given that there is more than one applicable method, a unique best method must be determined. In the case where there are only two methods each with only one parameter, the rule is that the conversion from the argument to the parameter type of one must be better than to the other.
The rules for what makes one conversion better than another is in section 7.5.3.5 of the specification, which I quote here for your convenience:
Given a conversion C1 that converts from a type S to a type T1, and a conversion C2 that converts from a type S to a type T2, C1 is a better conversion than C2 if at least one of the following holds:
• An identity conversion exists from S to T1 but not from S to T2
• T1 is a better conversion target than T2
Given two different types T1 and T2, T1 is a better conversion target than T2 if at least one of the following holds:
• An implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists
The purpose of this rule is to determine which type is more specific. If every Banana is a Fruit but not every Fruit is a Banana, then Banana is more specific than Fruit.
• T1 is a signed integral type and T2 is an unsigned integral type.
Run down the list. Is there an identity conversion from MyDerivedClass to either MyCastableClass or MyClass? No. Is there an implicit conversion from MyClass to MyCastableClass but not an implicit conversion going the other way? No. There is no reason to suppose that either type is more specific than the other. Are either integral types? No.
Therefore there is nothing upon which to base the decision that one is better than the other, and therefore this is ambiguous.
Is there anything wrong with this design?
The question answers itself. You've found one of the problems.
Intuitively there should be no ambiguity and the offending call should be resolved in the first method overload as MyDerivedClass is more closely related to MyClass
Though that might be intuitive to you, the spec does not make a distinction in this case between a user-defined conversion and any other implicit conversion. However I note that your distiction does count in some rare cases; see my article for details. (Chained user-defined explicit conversions in C#)
What it the logic behind the compiler error?
Well, the compiler determines the signature based on a few things. The number and type of the parameters is next to the name, one of the most important ones. The compiler checks if a method call is ambiguous. It doesn't only use the actual type of the parameter, but also the types it can be implicitly casted to (note that explicit casts are out of the picture, they are not used here).
This gives the issue you describe.
Is there anything wrong with this design?
Yes. Ambiguous methods are a source of a lot of problems. Especially when using variable types, like dynamic. Even in this case, the compiler can't choose which method to call, and that is bad. We want software to be deterministic, and with this code, it can't be.
You didn't ask for it, but I guess the best option is:
To rethink your design. Do you really need the implicit casts? If so, why do you need two methods instead of one?
Use explicit casting instead of implicit casting, to make casting a deliberate choice a compiler can understand.
In developing a class that should handle various generic lambda expressions, I fell into a rather familiar hole: I had a MyClass<T> class, and I tried to cast MyClass<string> to MyClass<object>, like so:
MyClass<string> myClassString = GetMyClass(); // Returns MyClass<String>
MyClass<object> myClassObject = myClassString;
Doing so returned an compilation error saying there there's no implicit conversion between the two types, but that an explicit conversion does exist. So I added the explicit conversion:
MyClass<object> myClassObject = (MyClass<object>)myClassString;
Now the code compiled, but failed in runtime, claiming the conversion is illegal.
I am using Visual Studio 2012, and the code is part of a Portable Class Library project compiled with C# 5.
Just to make sure, I replaced MyClass IList - the same behavior appeared - an explicit conversion is allowed, but fails during run-time.
Why? Why does the compiler accept this? What's the point of the explicit conversion if it fails in runtime?
In order to allow the cast, you need to mark it as covariant. However, covariance is only allowed for interfaces (and delegates). This would look like:
interface MyInterface<out T> ...
The reason why you can compile the explicit cast is probably that the compiler assumes that the return value of GetMyClass() could be a MyClass<object>. But That's hard to say without the declaration.
To be able to cast MyClass<string> to MyClass<object> you need to fulfill the following:
MyClass<T> must be an interface, e.g. IMyClass<T>.
You need to add the out keyword to the type parameter T, making the type parameter covariant.
The type parameter T may only appear in output positions of the members of the interface.
For example:
public interface IMyClass<out T>
{
T GetItem(); // T in an output position
}
Now you can cast it:
IMyClass<string> myClassString;
IMyClass<object> myClassObject = (IMyClass<object>)myClassString;
If you have classes A and B and you want to cast B to A then one of the following must be true:
B derives/implements A or vice versa
There is an explicit cast operator defined from B to A
None of the above is true in your case so the cast is invalid.
If your class implements IEnumerable you may use an extension method
using System.Linq
...
MyClass<Object> asObject = GetMyClass().Cast<Object>();
Otherwise, write an explicit operator or function that does the conversion:
public MyClass<Base> ConvertToBase<Base, Derived>(MyClass<Derived>) where Derived : Base
{
// construct and return the appropriate object
}
use Conversion operator to implement casting of your class to another classes
http://msdn.microsoft.com/en-us/library/85w54y0a.aspx
http://msdn.microsoft.com/en-us/library/09479473(v=vs.80).aspx
I have a generic function like this:
private LOCAL_TYPE RemoteToLocal<LOCAL_TYPE>(RemoteObjectBaseType remoteObject)
where LOCAL_TYPE: EntityBase
{
Type t = typeof(LOCAL_TYPE);
if (t == typeof(FavoritePlace))
{
return new FavoritePlace(remoteObject as RemotePlaceType1);
}
}
Where EntityBase is non-abstract class. FavoritePlace class is inherited from EntityBase.
However, I'm getting an error:
Cannot implicitly convert type Common.Model.FavoritePlace to 'LOCAL_TYPE'.
That makes me wonder: FavoritePlace is a child of EntityBase, and LOCAL_TYPE is constrained to be of type EntityBase. Why cannot the conversion happen? I'm probably missing something important here.
EDIT: Okay, based on current answers and some experiment I've found another workaround, which is to do following conversion:
if (t == typeof(FavoritePlace))
{
return (LOCAL_TYPE)(EntityBase)new FavoritePlace(remoteObject);
}
Now compiler is happy. But I'm just wondering, if such conversion is possible from compiler's perspective, why direct conversion to LOCAL_TYPE is not? Isn't is convertible to relationship transitive?
The problem is that FavoritePlace is not necessarily the type of LOCAL_TYPE.
If you have
class OtherEntity : EntityBase { }
then you can't return FavoritePlace when calling
var entity = RemoteToLocal<OtherEntity>(remoteObject);
If you know the conversion is safe you can get around it with a cast:
return (LOCAL_TYPE)(object)new FavoritePlace(remoteObject as RemotePlaceType1);
Although you have established through run-time code that LOCAL_TYPE is in fact FavoritePlace, the compiler does not have the same knowledge statically. The compiler expects you to return an object of type LOCAL_TYPE, matching exactly the type parameter of the method.
Thinks of this situation: someone makes the following call -
var res = RemoteToLocal<MostHatedPlace>(remoteObj); // MostHatedPlace derives from EntityBase
Now you're inside RemoteToLocal, you go through some conditions, and now it's time to return the result. You call
return new FavoritePlace(remoteObject as RemotePlaceType1);
You know that this branch in code is impossible to reach, because there is a run-time check guarding you from that:
if (t == typeof(FavoritePlace)) {
....
}
However, the compiler must assume that reaching this return statement is possible, which would be an error in cases when LOCAL_TYPE is not a FavoritePlace.
You may want to reconsider the use of generics here: from the code snippet it appears that you need the generic argument to avoid type-casting the result to the desired type in the caller. However, the caller would then need to perform an additional check to see if the conversion inside your RemoteToLocal has succeeded. In this case, a method
private EntityBase RemoteToLocal(RemoteObjectBaseType remoteObject) {
....
}
may be equally suited to the task, because it would be free of conversions that trick the compiler, and the structure of the calling code would remain the same.
Given a couple types like this:
interface I {}
class C : I {}
How can I do a static type cast? By this I mean: how can I change its type in a way that gets checked at compile time?
In C++ you can do static_cast<I*>(c). In C# the best I can do is create a temporary variable of the alternate type and try to assign it:
var c = new C();
I i = c; // statically checked
But this prevents fluent programming. I have to create a new variable just to do the type check. So I've settled on something like this:
class C : I
{
public I I { get { return this; } }
}
Now I can statically convert C to I by just calling c.I.
Is there a better way to do this in C#?
(In case anyone's wondering why I want to do this, it's because I use explicit interface implementations, and calling one of those from within another member function requires a cast to the interface type first, otherwise the compiler can't find the method.)
UPDATE
Another option I came up with is an object extension:
public static class ObjectExtensions
{
[DebuggerStepThrough]
public static T StaticTo<T>(this T o)
{
return o;
}
}
So ((I)c).Doit() could also be c.StaticTo<I>().Doit(). Hmm...probably will still stick with the simple cast. Figured I'd post this other option anyway.
Simply cast it:
(I)c
Edit Example:
var c = new C();
((I)c).MethodOnI();
Write an extension method that uses the trick you mentioned in your UPDATE:
public static class ObjectExtensions
{
public static T StaticCast<T>(this T o) => o;
}
To use:
things.StaticCast<IEnumerable>().GetEnumerator();
If things is, e.g., IEnumerable<object>, this compiles. If things is object, it fails.
// Compiles (because IEnumerable<char> is known at compiletime
// to be IEnumerable too).
"adsf".StaticCast<IEnumerable>().GetEnumerator();
// error CS1929: 'object' does not contain a definition for 'StaticCast'
// and the best extension method overload
// 'ObjectExtensions.StaticCast<IEnumerable>(IEnumerable)'
// requires a receiver of type 'IEnumerable'
new object().StaticCast<IEnumerable>().GetEnumerator();
Why Use a Static Cast?
One common practice during refactoring is to go ahead and make your changes and then verify that your changes have not caused any regressions. You can detect regressions in various ways and at various stages. For example, some types of refactoring may result in API changes/breakage and require refactoring other parts of the codebase.
If one part of your code expects to receive a type (ClassA) that should be known at compiletime to implement an interface (IInterfaceA) and that code wants to access interface members directly, it may have to cast down to the interface type to, e.g., access explicitly implemented interface members. If, after refactoring, ClassA no longer implements IIterfaceA, you get different types of errors depending on how you casted down to the interface:
C-style cast: ((IInterfaceA)MethodReturningClassA()).Act(); would suddenly become a runtime cast and throw a runtime error.
Assigning to an explicitly-typed variable: IInterfaceA a = MethodReturningClassA(); a.Act(); would raise a compiletime error.
Using the static_cast<T>-like extension method: MethodReturningClassA().StaticCast<IInterfaceA>().Act(); would raise a compiletime error.
If you expected your cast to be a downcast and to be verifiable at compiletime, then you should use a casting method that forces compiletime verification. This makes the intentions of the code’s original developer to write typesafe code clear. And writing typesafe code has the benefit of being more verifiable at compiletime. By doing a little bit of work to clarify your intention to opt into typesafety to both other developers, yourself, and the compiler, you magically get the compiler’s help in verifying your code and can catch repercussions of refactoring earlier (at compiletime) than later (such as a runtime crash if your code didn’t happen to have full test coverage).
var c = new C();
I i = c; // statically checked
equals to
I i = new C();
If you're really just looking for a way to see if an object implements a specific type, you should use as.
I i = whatever as i;
if (i == null) // It wasn't
Otherwise, you just cast it. (There aren't really multiple types of casting in .NET like there are in C++ -- unless you get deeper than most people need to, but then it's more about WeakReference and such things.)
I i = (I)c;
If you're just looking for a convenient way to turn anything implementing I into an I, then you could use an extension method or something similar.
public static I ToI(this I #this)
{
return #this;
}