我有一个抽象的Content
类和具体的子类
public abstract class Content
public class ContentA : Content
public class ContentB : Content
我也有一个抽象的泛型ContentSource
类和具体的子类
public abstract class ContentSource<T> where T : Content
public class SourceX : ContentSource<ContentA>
public class SourceY : ContentSource<ContentB>
我想要一个ContentSource<Content>
对象的列表,这些对象是ContentSource
的子类
var ContentSources = new List<ContentSource<Content>>
{
new SourceX(),
new SourceY(),
};
但这无法编译-我收到“无法从SourceX转换为ContentSource”错误。
为什么这不起作用?
答案 0 :(得分:5)
这可以使用covariance在C#中实现,但是您必须使用接口作为列表类型:
public interface IContentSource<out T> where T : Content {}
public class SourceX : IContentSource<ContentA> {}
public class SourceY : IContentSource<ContentB> {}
var ContentSources = new List<IContentSource<Content>>
{
new SourceX(),
new SourceY(),
};
Working example
这里对此进行了很好的解释:<out T>
vs <T>
in Generics
您仍然可以使用抽象类,但该列表仍必须是接口的列表:
public interface IContentSource<out T> where T : Content {}
public abstract class ContentSource<T> : IContentSource<T> where T : Content {}
public class SourceX : ContentSource<ContentA> {}
public class SourceY : ContentSource<ContentB> {}
对于类为什么不支持它也有很好的解释:Why does C# (4.0) not allow co- and contravariance in generic class types?
答案 1 :(得分:1)
尽管Kobi为您提供了一个完美的答案,但是我将给您一个简单的答案,为什么它不起作用。
在您的示例中,您想使用多态性来管理从类型基类的单个列表中的通用基类派生的不同类型。沿线的东西→
public abstract class Base {}
public class DerivedFirst : Base {}
public class DerivedSecond : Base {}
var first = new DerivedFirst();
var second = new DerivedSecond();
var list = new List<Base>{first,second}
这是很好的,因为它们是从常见的Base
类派生的。现在,让我们看看您的情况。但是在此之前,您应该了解Open Type
和Closed Type
之间的区别。简单地说,任何没有类型参数的泛型类型都是开放类型,无法实例化。 List<>
是open type
,而List<int>
是closed type
。创建closed type
时,它不会从其开放定义中派生。它本身就是一种全新的类型。
var i_am_false = typeof(List<int>).IsSubclassOf(typeof(List<>));//this is false
这是您的情况。您定义了将作为类型参数的类。
public abstract class Content
public class ContentA : Content
public class ContentB : Content
您在此处定义来源
public abstract class ContentSource<T> where T : Content
public class SourceX : ContentSource<ContentA>
public class SourceY : ContentSource<ContentB>
输入文字
您有SourceX
来自ContentSource<ContentA>
,而Object
来自SourceY
您有ContentSource<ContentB>
来自Object
,而var ContentSources = new List<ContentSource<Content>>
来自ContentSource<Content>
最后
您有ContentSource<ContentA>
,这是ContentSource<ContentB>
的列表,但与ContentSource<Content>
或M
毫无关系。就通用参数而言,它们只是具有相同的实现。
最后,让我们打电话
源自Object
的 ContentSource<ContentA>
类N
Object
的{{1}}类ContentSource<ContentB>
,
O
类Object
的派生自public class SourceX : N{}
public class SourceY : O{}
var ContentSources = new List<M>{
new SourceX(),
new SourceY(),
};
看看你在做什么→
<div class="section_content">
<div class="grid clearfix">
<div>
{% load blog_tags keyword_tags mezzanine_tags i18n %}
{% blog_recent_posts 1 as recent_posts %}
{% if recent_posts %}
{% for recent_post in recent_posts %}
<div class="card card_largest_with_image grid-item">
{% spaceless %}
<a class="text-capitalize" href="{{ recent_post.get_absolute_url }}">
{% if settings.BLOG_USE_FEATURED_IMAGE and recent_post.featured_image %}
<img class="card-img-top" src="{{ MEDIA_URL }}{% thumbnail recent_post.featured_image 610 193 %}">
{% endif %}
</a>
{% endspaceless %}
<div class="card-body">
<div class="card-title"><a href="{{ recent_post.get_absolute_url }}">{{ recent_post.title }}</a></div>
<p class="card-text">{{ recent_post.description|safe }}</p>
<small class="post_meta"><span>{{ recent_post.publish_date|timesince }} {% trans "ago" %}</span></small>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% blog_recent_posts 5 as recent_posts %}
{% if recent_posts %}
{% for recent_post in recent_posts %}
<div class="card card_default card_small_with_background grid-item">
{% spaceless %}
<a class="text-capitalize" href="{{ recent_post.get_absolute_url }}">
{% if settings.BLOG_USE_FEATURED_IMAGE and recent_post.featured_image %}
<div class="card_background" style="background-image:url({{ MEDIA_URL }}{% thumbnail recent_post.featured_image 263 165 %}); height: 163px; width:265px;"></div>
{% endif %}
{% endspaceless %}
<div class="card-body">
<div class="card-title card-title-small"><a href="{{ recent_post.get_absolute_url }}">{{
recent_post.title }}</a></div>
<small class="post_meta"><span>{{ recent_post.publish_date|timesince }} {% trans "ago" %}</span></small>
</div>
</div>
{% endfor %}
{% endif %}
</div>
当然,它是行不通的:)。 最后,为什么它可以使用协方差,请查看Kobi的答案。