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!
Related
Have the following code which works fine.
MyType convertedItem = (MyType)item;
However I get a compiler error from
var convertedItem = item as MyType;
Cannot convert type 'OtherType' to 'MyType' via a reference
conversion, boxing conversion, unboxing conversion, wrapping
conversion, or null type conversion.
Can anyone explain why \ when this occurs. An explicit cast works fine but AS wont even compile.
** How do I get 'AS' functionality in this situation. Namely I need to do a trycast and would prefer not to invoke the exceptionhandler to accomplish it. **
as doesn't work with anything that is a struct. Logically we can understand this because a struct is non nullable by default. The suggestions of casting to object work by cheating and boxing the struct
For example, the following types would give CS0039:
class MyType
{
}
class MyOtherType
{
}
MyOtherType item = new MyOtherType();
var convertedItem = item as MyType;
In the above example, the compiler has determined that given the types participating in the cast, it's impossible to perform the requested conversion.
Here providing conversion operators would solve the problem.
EDIT: working around this error with casting to Object is not recommended, as it defeats the purpose of the type system
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.
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.
Why is this a compile time error?
public TCastTo CastMe<TSource, TCastTo>(TSource i)
{
return (TCastTo)i;
}
Error:
Cannot convert type 'TSource' to 'TCastTo'
And why is this a runtime error?
public TCastTo CastMe<TSource, TCastTo>(TSource i)
{
return (TCastTo)(object)i;
}
int a = 4;
long b = CastMe<int, long>(a); // InvalidCastException
// this contrived example works
int aa = 4;
int bb = CastMe<int, int>(aa);
// this also works, the problem is limited to value types
string s = "foo";
object o = CastMe<string, object>(s);
I've searched SO and the internet for an answer to this and found lots of explanations on similar generic related casting issues, but I can't find anything on this particular simple case.
Why is this a compile time error?
The problem is that every possible combination of value types has different rules for what a cast means. Casting a 64 bit double to a 16 bit int is completely different code from casting a decimal to a float, and so on. The number of possibilities is enormous. So think like the compiler. What code is the compiler supposed to generate for your program?
The compiler would have to generate code that starts the compiler again at runtime, does a fresh analysis of the types, and dynamically emits the appropriate code.
That seems like perhaps more work and less performance than you expected to get with generics, so we simply outlaw it. If what you really want is for the compiler to start up again and do an analysis of the types, use "dynamic" in C# 4; that's what it does.
And why is this a runtime error?
Same reason.
A boxed int may only be unboxed to int (or int?), for the same reason as above; if the CLR tried to do every possible conversion from a boxed value type to every other possible value type then essentially it has to run a compiler again at runtime. That would be unexpectedly slow.
So why is it not an error for reference types?
Because every reference type conversion is the same as every other reference type conversion: you interrogate the object to see if it is derived from or identical to the desired type. If it's not, you throw an exception (if doing a cast) or result in null/false (if using the "as/is" operators). The rules are consistent for reference types in a way that they are not for value types. Remember reference types know their own type. Value types do not; with value types, the variable doing the storage is the only thing that knows the type semantics that apply to those bits. Value types contain their values and no additional information. Reference types contain their values plus lots of extra data.
For more information see my article on the subject:
http://ericlippert.com/2009/03/03/representation-and-identity/
C# uses one cast syntax for multiple different underlying operations:
upcast
downcast
boxing
unboxing
numeric conversion
user-defined conversion
In generic context, the compiler has no way of knowing which of those is correct, and they all generate different MSIL, so it bails out.
By writing return (TCastTo)(object)i; instead, you force the compiler to do an upcast to object, followed by a downcast to TCastTo. The compiler will generate code, but if that wasn't the right way to convert the types in question, you'll get a runtime error.
Code Sample:
public static class DefaultConverter<TInput, TOutput>
{
private static Converter<TInput, TOutput> cached;
static DefaultConverter()
{
ParameterExpression p = Expression.Parameter(typeof(TSource));
cached = Expression.Lambda<Converter<TSource, TCastTo>(Expression.Convert(p, typeof(TCastTo), p).Compile();
}
public static Converter<TInput, TOutput> Instance { return cached; }
}
public static class DefaultConverter<TOutput>
{
public static TOutput ConvertBen<TInput>(TInput from) { return DefaultConverter<TInput, TOutput>.Instance.Invoke(from); }
public static TOutput ConvertEric(dynamic from) { return from; }
}
Eric's way sure is shorter, but I think mine should be faster.
The compile error is caused because TSource cannot be implicitly cast to TCastTo. The two types may share a branch on their inheritance tree, but there is no guarantee. If you wanted to call only types that did share an ancestor, you should modify the CastMe() signature to use the ancestor type instead of generics.
The runtime error example avoids the error in your first example by first casting the TSource i to an object, something all objects in C# derive from. While the compiler doesn't complain (because object -> something that derives from it, could be valid), the behaviour of casting via (Type)variable syntax will throw if the cast is invalid. (The same problem that the compiler prevented from happening in example 1).
Another solution, which does something similar to what you're looking for...
public static T2 CastTo<T, T2>(T input, Func<T, T2> convert)
{
return convert(input);
}
You'd call it like this.
int a = 314;
long b = CastTo(a, i=>(long)i);
Hopefully this helps.