2009-09-16 65 views
2

我有一个视图的HtmlHelper <ChildType>不能分配给的HtmlHelper <MotherType>

ViewUserControl<SearchViewData> 

其中

SearchViewData: CommonViewData 

在此视图中我因此具有为Html的参考。
这是HtmlHelper<SearchViewData>

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

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

由于SearchViewData从CommonViewData继承和我的HTML是键入HtmlHelper < SearchViewData>它因此也是HtmlHelper < CommonViewData>。
但是,当我尝试访问TranslatedApplicationSelectList方法时,它在我的视图中出现错误,指出HtmlHelper < SearchViewData>不能分配给HtmlHelper < CommonViewData>。

这是我的面向对象逻辑中的缺陷吗?这是C#如何在泛型中处理继承的限制(我认为Skeet曾经向我解释过这一点,但我找不到该帖子了)?

最重要的是,我该如何解决它?

回答

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的文章。

+0

是的,那些事情解释我早些时候由约翰Skeet。我有一种感觉,这是我的问题的原因,但不确定和不知道条款,所以再次找不到问题。 所以对我的问题的唯一解决方案是创建一个方法,接受HtmlHelper ,并写另一个,如果我想要在另一种类型上执行:S 不会有语法来“铸造”您的泛型类型也可以接受吗?它将把责任推给程序员,就像普通演员一样。 – 2009-09-16 09:23:09

1

如果您implmentation否则将允许你,你正在使用的HtmlHelper<CommonViewData>使用一个HtmlHelper<SearchViewData>,那么你应该能够声明您的扩展方法是这样,而不是:

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

这确实是我正在做的,但这意味着我不能在其他视图中重用其他子类用作viewdata的方法。 – 2009-09-17 13:39:29

+0

@boris - 我不确定我是否理解为什么会这样 - 因为扩展方法是通用的,您可以将它用于任何子类... – kvb 2009-09-17 18:02:30