Just came across this:
Func<List<object>> foo = () => new List<object>();
List<string> s = (List<string>)foo();
IList<string> s1 = (IList<string>)foo();
Compiler complains about casting to List (makes sense), but says nothing about IList. Makes me wonder why is that?
The compiler knows that a List<X> cannot be a List<Y>.
It therefore gives a compiler error.
However, the second cast could succeed if the List<X> is actually some derived class that also implements IList<Y>.
You will only get a compile-time error from a cast if neither type is an interface, or if one type is an unrelated interface and the other type is sealed (or a struct).
To quote the spec (ยง6.4.2)
The explicit reference conversions are:
From object and dynamic to any other reference-type.
From any class-type S to any class-type T, provided S is a base class of T.
From any class-type S to any interface-type T, provided S is not sealed and provided S does not implement T.
From any interface-type S to any class-type T, provided T is not sealed or provided T implements S.
From any interface-type S to any interface-type T, provided S is not derived from T.
[snip]
(emphasis added)
The provided... clauses exclude conversions that are actually implicit.
An object that is known to be a List<object> might implement IList<string> as well as IList<object>, so it's possible that the cast can succeed. It can't in this case because we know that the statement is simply new List<object>(), but the compiler doesn't consider that. You might've extended List<T> and implemented the other, e.g.
// not recommended, but second cast works
public class MyWeirdList : List<object>, IList<string>
An object that is known to be a List<object> cannot possibly also be a List<string>, because you can only inherit from a single type.
public class MyWeirdList : List<object>, List<string> // compiler error
If List<T> were sealed, both casts would be invalid, because then the compiler would know for sure that the class couldn't implement IList<string>. You can try this by using this class instead:
public sealed class SealedList<T> : List<T> { }
The first line fails at compile time, the second gives an "Unable to cast object of type 'System.Collections.Generic.List1[System.Object]' to type 'System.Collections.Generic.IList1[System.String]'." exception during runtime.
If you look at this question (Cast IList<string> to IList<object> fails at runtime), the answer clarifies why this compile works and also provides an example for a class that could satisfy the conditions provided.
Related
Say I instantiate a generic class with a covariant type parameter which is a struct, then I cast the newly created object as itself with a type parameter of object in the place of struct, the cast will fail though the variance should allow for it.
Example:
public class Succeeds {}
public struct Fails {}
var castSucceeds = (IEnumerable<object>)Enumerable.Empty<Succeeds>();
var castFails = (IEnumerable<object>)Enumerable.Empty<Fails>();
As you can see from the above this cast works thanks to the generic type of IEnumerable<T> being covariant, but when attempted with a struct instead of a class it fails. I suspect the failure is related to the need for boxing when casting a struct to an object.
Is there any way around this or am I perhaps looking at it wrong?
According to Microsoft:
Variance applies only to reference types; if you specify a value type
for a variant type parameter, that type parameter is invariant for the
resulting constructed type.
Try doing a manual cast:
var castFails = Enumerable.Empty<Fails>().Cast<object>();
For example, if you run the following code...
Type IListType = new List<string>().GetType()
.GetInterface("IList`1")
.GetGenericTypeDefinition();
...and you watch IListType variable, you'll find that the whole Type instance has all properties available like FullName and others.
But what happens when you run the code bellow?
Type IListType2 = typeof(List<>).GetInterface("IList`1")
Now IListType got from a generic type definition isn't the same as the first code sample: most Type properties will return null.
The main issue with this is that IListType == IListType2 doesn't equal while they're the same type.
What's going on?
This is ugly...
Now see what happens if you call IListType2.GetGenericTypeDefinition()... It recovers the type information!
It would be great that a .NET Framework development team member could explain us why an already generic type definition which has strangely lost its metadata has IsGenericTypeDefinition property set to false while it's still a generic type definition, and finally, if you call GetGenericTypeDefinition() on it, you recover the type information.
This is strange...
The following equality will be true:
Type IListType = new List<string>().GetType()
.GetInterface("IList`1")
.GetGenericTypeDefinition();
// Got interface is "like a generic type definition" since it has
// no type for T generic parameter, and once you call
// GetGenericTypeDefinition() again, it recovers the lost metadata
// and the resulting generic type definition equals the one got from
// List<string>!
Type IListType2 = typeof(List<>).GetInterface("IList`1").GetGenericTypeDefinition();
bool y = IListType == IListType2;
The following types are all different and not connected by an inheritance relationship:
IList<T>
IList<int>
IList<string>
All of these have different Type objects because you can do different things with them. The latter two are the specializations of the former. The first is the generic type definition (which you can obtain through GetGenericTypeDefinition).
There is another part to the explanation. When you say class List<T> : IList<T> then the IList<T> part is not equal to typeof(IList<>) because it is already specialized to T. This is no longer a generic type definition. It is a concrete type such as IList<int>. It is specialized to bind its only type argument to the T that List<T> was specialized to.
Experiment for LINQPad:
Type bound = new List<string>().GetType().GetInterface("IList`1");
bound.GenericTypeArguments.Single().Dump(); //string
Type bound = typeof(List<>).GetInterface("IList`1");
bound.GenericTypeArguments.Single().Dump(); //"T"
(bound.GenericTypeArguments.Single() == typeof(List<>).GetGenericArguments().Single()).Dump(); //true
The first version of IList<T> is the actual typed version of IList<T>, let's say IList<string>.
The second one is the generic definition of IList<T> without a type for T.
That makes the two interfaces different. There are not the same, since the first is a concrete version of the second.
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 created an Class which is only able to handle primitive (or ICloneable) Types
I want to know if it's possible to say something like:
public myobject(primitiv original){...}
or do I really need to create a constructor for each primitive type like:
public myobject(int original){...}
public myobject(bool original){...}
...
What I am trying to achieve is to create an object with 3 public properties Value, Original and IsDirty.
The Value will be an deep Clone of Original so the Original needs to be primitve or ICloneable
Primitive types in C# are defined as structs (implemented generally as ValueType in the .NET CLR). I believe you have two options:
As has been said already: Receive any type, check it against every acceptable type, throw an exception if it doesn't match.
Make your class generic, make the constructor generic with a constraint of where T : struct (with T being the type parameter). This will catch all structs, not just the primitive types, but I think that's the best you can hope for without manual checking and with compile-time checking. You can mix this constraint with other ones, of course.
And you can combine the two options above to have some of the checking be done at compile-time and some of it be done at run-time.
If you want to do that to force whomever is using your API to use such types (through compile time errors should they use the wrong types), I'm afraid it can't be done.
You could, however, receive an object in the constructor, evaluate its type, and throw an ArgumentException in case the parameter is neither one of the "primitive" types nor implements ICloneable.
Edit: This might be useful. You can determine whether a variable belongs to a primitive type with the following code:
Type t = foo.GetType();
t.IsPrimitive; // so you don't have to do an evaluation for each primitive type.
It is not exactly what you asked, but you can have 2 constructors, one for structs and one for ICloneable:
public myobject(System.ValueType original){...}
public myobject(ICloneable original){...}
How about generics instead of reflection?
public class MyObject<T>
where T: IComparable
{
public MyObject(T original)
{
// do runtime check
}
}
var c1 = new MyObject<int>(1);
// or
var c2 = new MyObject<Int32>(2);
What is the difference between covariance and upcasting, or, more specifically, why are they given different names?
I've seen the following example referred to as 'upcasting':
string s = "hello";
object o = s; //upcast to 'string' to 'object'
Whereas, the following I have seen called 'covariance':
string[] s = new string[100];
object[] o = s;
IEnumerable<string> ies = new List<string>();
IEnumerable<object> ieo = ies;
Now, to my untrained eye, covariance seems to be the same as upcasting, except that it refers the casting of collections. (And of a similar statement can be made regarding contravariance and downcasting).
Is it really that simple?
Now, to my untrained eye, covariance seems to be the same as upcasting, except that it refers the casting of collections. (And of a similar statement can be made regarding contravariance and downcasting).
Is it really that simple?
Covariance isn't about upcasting, although I can see why you think it's related.
Covariance is about the following very simple idea. Let's say you have a variable derivedSequence of type IEnumerable<Derived>. Let's say you have a variable baseSequence of type IEnumerable<Base>. Here, Derived derives from Base. Then, with covariance, the following is a legal assignment, and an implicit reference conversion occurs:
baseSequence = derivedSequence;
Note that this is not upcasting. It is not the case that IEnumerable<Derived> derives from IEnumerable<Base>. Rather, it is covariance that allows you to assign the value of the variable derivedSequence to the variable baseSequence. The idea is that variables of type Base can be assigned from objects of type Derived, and since IEnumerable<T> is covariant in its parameter, objects of type IEnumerable<Derived> can be assigned to variables of type IEnumerable<Base>.
Of course, I haven't yet really explained what covariance is. In general, covariance is about the following simple idea. Let's say you have a mapping F from types to types (I'll denote this mapping by F<T>; given a type T its image under the mapping F is F<T>.) Let's say that this mapping has the following very special property:
if X is assignment compatible with Y, then F<X> is assignment compatible with F<Y> as well.
In this case, we say that F is covariant in its parameter T. (Here, to say that "A is assignment compatible with B" where A and B are reference types means that instances of B can be stored in variables of type A.)
In our case, IEnumerable<T> in C# 4.0, an implicit reference conversion from instances of IEnumerable<Derived> to IEnumerable<Base> if Derived is derived from Base. The direction of assignment compatibility is preserved, and this is why we say that IEnumerable<T> is covariant in its type parameter.
Casting refers to changing the static type of objects and expressions.
Variance refers to the interchangeability or equivalence of types in certain situations (such as parameters, generics, and return types).
IEnumerable<string> is not derived from IEnumerable<object>, so the cast between them is not upcasting. IEnumerable is covariant in its type parameter and string is derived from object, so the cast is allowed.
The reason they are different concepts is that, unlike upcasting, covariance is not always allowed. It would have been easy for the designers of the type-system to make IList<Cat> be considered as "derived" from IList<Animal>, but then we run into problems:
IList<Cat> cats = new List<Cat>();
IList<Animal> animals = cats;
animals.Add(new Dog()); //Uh oh!
If this were allowed, now our cats list would contain a Dog!
In contrast, the IEnumerable<T> interface has no way of adding elements, so this is perfectly valid (in C# 4.0):
IList<Cat> cats = new List<Cat>();
IEnumerable<Animal> animals = cats;
//There's no way to add things to an IEnumerable<Animal>, so here we are ok
Thie blog post below has a good explanation of it:
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
From what I can gather covariance removes the need for explicit downcasting subsequent to a previous upcast. Typically if you upcast an object you can only access the base type methods and attributes, with covariance it seems you can imply the downcast by replacing lesser derived types with more derived types in the more derived class declaration.