This might be a pretty simple question, but something doesn't make sense to me.
Given this class:
public class Person : ICloneable {
public object Clone()
{
Console.WriteLine("Hello, world");
return new Person();
}
}
Why is this ok?
List<Person> people = new List<Person> { new Person() };
IEnumerable<ICloneable> clonables = people;
But this isn't?
List<Person> people = new List<Person> { new Person() };
IList<ICloneable> clonables = people;
Why is it I can assign to an IEnumerable IClonable, but not an IList ICloneable?
This is called covariance. Eric Lippert and Jon Skeet (among others) gave some nice explanations of covariance (and its twin, contravariance) in answers to this question: Difference between Covariance & Contra-variance
Very basically, you can enumerate over a list of Person
just like you would do over a list of ICloneable
, no problem could occur because you can't change the enumeration. But you can't assign your list of Person
to a list of ICloneable
because then you could later try, for example, to insert some other derivative of ICloneable
in it, which would result in a strong violation of type-safety.
IList:
public interface IList<T> : ICollection<T>,
IEnumerable<T>, IEnumerable
IEnumerable:
public interface IEnumerable<out T> : IEnumerable
Notice the out
in IEnumerable
? IEnumerable<T>
is covariant
I had a different answer, which was wrong. I apologize. Thanks Matt for pointing this out.
The error message is quite misleading. It suggests a cast will work, but does not. The problem is that the conversion of Person to ICloneable may require adjusting the pointer so that the virtual function table is correct for a generic ICloneable. That means every element in the list may need an adjustment. The real fix is to use ToList:
IList<ICloneable> clonablesA = people.ToList<ICloneable>();
Ignore some of the comments below, since I completely erased my first answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With