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:
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, butpublic void MyMethod(T myParam)
is not allowed, because this goes into the class;Because of this restriction, .NET knows that
T
can be cased to everything that inherits fromT
. 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
.
精彩评论