我有一个观点
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曾经解释过我这个,但我找不到帖子了吗?)
最重要的是,如何修复它?
答案 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