开发者

Why can't a list of Interfaces use an implementing type?

There must be something fundamental about interfaces/generics I have not yet learned. I hope to learn it now.

Here is the scenario:

I have this interface and class:

public interface IInterface
{
    string TestValue { get; set; }
}

public class RealValue: IInterface
{
    public string TestValue { get; set; }
}

If I create a method like this it compiles just fine:

public class RandomTest: IMethodInterface
{
   public IInterface GetRealValue()
   {
       RealValue realValue = new RealValue();
       return realValue;
   }
 }

Note that I am returning an object that implements the interface.

Now, if I add to the RandomTest class a method that returns list then it does not work anymore:

 public List<IInterface> GetRealValues()
 {
    List<RealValue> realValues = new List<RealValue>();
    return realValues;  // ERROR Here <- says it can't convert to a List<IInterface>
 }

So, my guess is that generics can't figure this out, but why?

Is there a way around this? What do you do when the return value of the method above is l开发者_如何转开发ocked because you are implementing an interface like this:

public interface IMethodInterface
{
    IInterface GetRealValue();
    List<IInterface> GetRealValues(); // Can't just convert the return types to a concrete 
                                      // class because I am implementing this.  This 
                                      // interface is in a separate project that does not 
                                      // have the concrete classes.
}

Is there any hope? What would you do?


The reason for this is that List<RealValue> is a specific type, which does not inherit List<IInterface>, so it cannot be converted.

However, in .NET 4.0 you're in luck. The interface IEnumerable<out T> specifies that T can be the class, or a base class, so you can change your method to:

IEnumerable<IInterface> GetRealValues();

on .NET 4.0. Note that this only works because IEnumerable has the out keyword specified on the template parameter.

The out keyword means two things:

  1. The type before which you put the out keyword can only be used for types that go out of the class. So, public T MyMethod() is allowed, but public void MyMethod(T myParam) is not allowed, because this goes into the class;

  2. Because of this restriction, .NET knows that T can be cased to everything that inherits from T. Because of the restriction, this is guaranteed to be a safe operation.


Note that if you could convert List<RealValue> to List<IInterface> you could call .Add(anyObjectImplementingIInterface) which cannot work.

You can, however, use .Cast<IInterface>().ToList().


A List<RealValue> cannot be used in place of a List<IInterface>. If it was permitted, the caller would be able to Add an IInterface to the returned list that is of a type other than RealValue.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜