IEnumerable Assignment (Covariance)

Since IEnumerable has a covariant parameter in C # 4.0, I am confused how it behaves in the following code.

 public class Test { IEnumerable<IFoo> foos; public void DoTestOne<H>(IEnumerable<H> bars) where H : IFoo { foos = bars; } public void DoTestTwo(IEnumerable<IBar> bars) { foos = bars; } } public interface IFoo { } public interface IBar : IFoo { } 

Thus, basically the DoTestOne method DoTestOne not compile while DoTestTwo does. In addition to why this doesn't work, if anyone knows how I can achieve the DoTestOne effect (by assigning IEnumberable<H> where H : IFoo IEnumberable<IFoo> ), I would appreciate help.

+7
source share
4 answers

If you know that H will be a class, this works:

  public void DoTestOne<H>(IEnumerable<H> bars) where H : class, IFoo { foos = bars; } 

The problem here is that if H is a value type, covariance is not quite what you expect, since IEnumerable<MyStruct> actually returns value types, while IEnumerable<IFoo> should return boxed instances. You can use the explicit Cast<IFoo> to get around this if necessary.

+9
source

You just need an IEnumerable<IFoo> listing there:

 public void DoTestOne<H>(IEnumerable<H> bars) where H : IFoo { foos = (IEnumerable<IFoo>)bars; } 

Editing courtesy of Dan Bryant: using foos = bars.Cast<IFoo>() instead of the above covers an InvalidCastException when H is a struct .

+3
source

You forgot the cast in your return or the class identifier in your general constraint. What you do, of course, is perhaps lower.

From: http://msdn.microsoft.com/en-us/library/d5x73970.aspx

 where T : <interface name> The type argument must be or implement the specified interface. Multiple interface constraints can be specified. The constraining interface can also be generic. 
0
source

Within the .net Runtime, each value type has an associated type of heap object of the same name. In some contexts, the value type will be used; in other contexts, the type of heap. When a storage location (variable, parameter, return value, field or array) of value type is declared, this storage location will contain the actual contents of this type. When the location of the class type is declared, it will contain either null or a reference to the heap object that is stored elsewhere. Interface type storerooms are treated as reference types and contain heap references, even if some (or all) of the interface implementations are actually value types.

Attempting to save the value type in the storage of the reference type will lead to the creation of a new instance of the heap type associated with the value type, copy all the fields from the original storage location into the corresponding fields in the new instance and save the link to this instance, a process called "boxing". An attempt to specify a link to a heap in the data store of a value type will check if it refers to an instance of the heap type associated with the value type; if so, the fields of the heap object will be copied ("unboxed") to the corresponding type values ​​in the store.

Although it may seem that the type of type System.Int32 comes from System.Object , this is only half true. There is a type of the System.Int32 heap object that is actually derived from System.Object , but a variable of type System.Int32 does not contain a reference to such an object. Instead, such a variable contains the actual data associated with this integer; the data itself is just a collection of bits and nothing happens.

If you think that the storage locations in the type interface contain “something derived from System.Object that implements the _ interface”, then instances of any type of class that implements this interface are an instance of this type, but instances of value types are even if they are converted to other types, they are not instances of any other types. Code that uses IEnumerator<IFoo> does not just want its Current method to return what can be convertible to IFoo , or implement IFoo ; he wants to return what is derived from Object , which implements IFoo . Therefore, to replace IEnumerable<T> with IEnumerable<IFoo> it is necessary for T be limited both to implement IFoo and to be its own derivative from System.Object .

0
source

All Articles