[英]Why can't a method declare return type `List<IMyInterface>` and return a concrete class implementing it
I have the following interface 我有以下界面
public interface IMyInterface
{
// Some method and property signatures
}
I have the following class implementing the above interface 我有以下类实现上面的接口
public class MyClass : IMyInterface
{
// Some methods and properties as declared by IMyInterface
}
Then I have this method in some random class, that I want to return a list of objects implementing IMyInterface
. 然后我在一些随机类中有这个方法,我想返回一个实现
IMyInterface
的对象列表。 In this particular implementation these objects are instances of MyClass
. 在这个特定的实现中,这些对象是
MyClass
实例。
public List<IMyInterface> getItems(int id)
{
return new List<MyClass>();
}
This will result in a compile error (Visible in real time as well, in Visual Studio) 这将导致编译错误(在Visual Studio中也可实时显示)
Cannot implicitly convert type 'System.Collections.Generic.List<MyClass>' to 'System.Collections.Generic.List<IMyInterface>'
无法将类型'System.Collections.Generic.List <MyClass>'隐式转换为'System.Collections.Generic.List <IMyInterface>'
I've searched the internet and finally found this thread C# Interfaces and Generic Lists I then ended up with the following method 我搜索了互联网,最后找到了这个线程C#接口和通用列表 ,然后我最终得到了以下方法
public List<IMyInterface> getItems(int id)
{
return new List<MyClass>().Cast<IMyInterface>().ToList();
}
This will compile, but to me it seem to be a really odd way to handle it; 这将编译,但对我来说,处理它似乎是一种非常奇怪的方式; Casting a concrete class to an Interface.
将具体类转换为接口。 In the thread C# Interfaces and Generic Lists Aequitarum Custos comment to the accepted answer indicate that this should not have to be done.
在线程C#接口和通用列表 Aequitarum Custos对接受的答案的评论表明不应该这样做。
Am I missing something or is this the way to do it? 我错过了什么或这是这样做的方式吗?
Because even though Base
is a subtype of Parent
, doesnt mean List<Base>
is a subtype of List<Parent>
. 因为即使
Base
是Parent
的子类型,也不意味着List<Base>
是List<Parent>
的子类型。 IList<T>
is invariant in its generic parameter, and so is List<T>
(c# doesn't support class variance, only interface variance). IList<T>
在其泛型参数中是不变的,因此List<T>
(c#不支持类方差,只支持接口方差)。
Read more about covariance, contravariance and invariance here: http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx 阅读更多关于协方差,逆变和不变性的信息: http : //blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
If List<T>
was covariant, and you were allowed to do this: 如果
List<T>
是协变的,那么你被允许这样做:
List<Parent> list = new List<Base>();
What would happen if you then did this? 如果你这样做会怎么样?
list.Add(new OtherBase());
This would certainly be legal at compile time, but cause a runtime error. 这在编译时肯定是合法的,但会导致运行时错误。
This is because T
parameter in List<T>
is not covariant . 这是因为
List<T>
T
参数不是协变的 。 But it is in IEnumerable<out T>
: 但它在
IEnumerable<out T>
:
out T
出来
The type of objects to enumerate.
要枚举的对象的类型。
This type parameter is covariant.
此类型参数是协变的。 That is, you can use either the type you specified or any type that is more derived.
也就是说,您可以使用指定的类型或更多派生的类型。
So you can do this, if you'd consider to change signature of getItems
: 如果您考虑更改
getItems
签名,那么您可以这样做:
public IEnumerable<IMyInterface> getItems(int id)
{
return new List<MyClass>() as IEnumerable<IMyInterface>;
}
You can find more information about covariance and contravariance here . 您可以在此处找到有关协方差和逆变的更多信息。
Consider this example: 考虑这个例子:
public interface IAnimal
{
}
public class Cat : IAnimal
{
}
public class Dog : IAnimal
{
}
And you equivalent method: 而你等效的方法:
public List<IAnimal> getAnimals()
{
return new List<Dog>();
}
// You just Dog'd a list of Cats
IEnumerable<Cat> cats = getAnimals();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.