HtmlHelper <childtype>不能分配给HtmlHelper <mothertype> </mothertype> </childtype>

时间:2009-09-16 08:16:39

标签: c# .net generics oop

我有一个观点

ViewUserControl<SearchViewData>

其中

SearchViewData: CommonViewData

在这个视图中,我因此引用了Html 这是HtmlHelper<SearchViewData>

类型

我创建了一个名为CommonHtmlHelper的自定义HtmlHelper类,我想要这个(注意HtmlHelper参数的类型):

 public static SelectList TranslatedApplicationSelectList(this HtmlHelper<CommonViewData> htmlHelper, string selectedCode)

由于SearchViewData继承自CommonViewData,而我的Html类型为HtmlHelper&lt; SearchViewData&gt;因此它也是HtmlHelper&lt; CommonViewData&gt; 然而,当我尝试访问TranslatedApplicationSelectList方法时,我在我的视图中得到一个错误,说HtmlHelper&lt; SearchViewData&gt;不能分配给HtmlHelper&lt; CommonViewData&gt;。

这是我的OO逻辑中的一个缺陷吗?这是C#如何处理泛型中的继承的限制(我想Skeet曾经解释过我这个,但我找不到帖子了吗?)

最重要的是,如何修复它?

2 个答案:

答案 0 :(得分:3)

.NET 3.5不处理Covariance and Contravariance,因此.NET 3.5中唯一兼容的泛型类型是完全相同的类型。

应该允许这样做的一个例子:

public class BaseType { }
public class DerivedType : BaseType { }

public void DumpList(List<BaseType> list)
{
    foreach (var o in list)
        Debug.WriteLine(o);
}

...
List<DerivedType> objects = new List<DerivedType>();
objects.Add(new DerivedType());
DumpList(objects);

这里我们只是从对象中转储内容(即读取),这应该是安全的。

更好的例子,为什么允许:

public class BaseType { }
public class DerivedType : BaseType { }

public void ManipulateList(List<BaseType> list)
{
    list.Add(new BaseType());
}

...
List<DerivedType> objects = new List<DerivedType>();
objects.Add(new DerivedType());
ManipulateList(objects);

这里我们尝试将BaseType的对象添加到已声明为存储DerivedType对象的列表中。这是不允许的。

由于编译器无法区分这两种情况,因为上面的第二种情况,它们都是不允许的。

在.NET 4.0和C#4.0中,您可以应用额外的语法,指定允许转换泛型类型的方向,具体取决于您打算如何处理对象。这可能允许两个示例中的第一个工作,但在.NET 3.5中,这是不可能的。第二个示例在C#4.0中不起作用。

以下是Charlie Calvert关于Covariance and Contravariance in C# 4.0的文章。

答案 1 :(得分:1)

如果您的实施方式允许您使用HtmlHelper<SearchViewData>,而您当前正在使用HtmlHelper<CommonViewData>,那么您应该能够声明您的扩展方法:

public static SelectList TranslatedApplicationSelectList<T>(this HtmlHelper<T> htmlHelper, string selectedCode) where T : CommonViewData