扩展方法不适用于Inhierited类型

时间:2014-10-09 11:31:53

标签: c# extension-methods covariance

我有以下实现接口的类:

public class Category : IHierarchical<Category> {
    ...
}

然后我有一个名为ProductCategory的继承类型:

public class ProductCategory : Category {
    ...
}

这是我的IHierachical界面:

public interface IHierarchical<out T> where T : IHierarchical<T> {
    T Parent { get; }
    IEnumerable<T> Children { get; }
}

最后我有以下扩展方法:

public static string MyExtension<T>(this T item) where T : IHierarchical<T> {
    ...
}

如果我有类别类型的实例,我可以成功调用我的扩展方法。但是,如果我的实例是ProductCategory类型,我无法调用它的扩展方法,而是我收到错误:

The type 'ProductCategory' cannot be used as type parameter 'T' in the generic
type or method 'IHierarchicalExtensions.MyExtension<T>(T, string)'. There is no
implicit reference conversion from 'ProductCategory' to
'IHierarchical<ProductCategory>'.

我认为通过制作IHierachical协变,它可以解决这个问题。如果有人能告诉我如何做到这一点,我会很感激。感谢

4 个答案:

答案 0 :(得分:2)

您的问题是ProductCategory不符合约束where T : IHierarchical<T>,因为ProductCategory实际上是IHierarchical<Category>,因为它从Category继承了ProductCategory。至于如何解决这个问题取决于你想要完成的事情。您可以放弃约束或更改IHierarchical<ProductCategory>以实施Category(它仍可继承ProductCategory)或将Category投放到T,或者当您调用扩展方法时,最后将Category的类型指定为{{1}}。

答案 1 :(得分:2)

我认为你有类似的东西:

Category c = new Category();
ProductCategory pc = new ProductCategory();

c.MyExtension();
pc.MyExtension();//Compiler error!

您的扩展方法允许T,这意味着您可以传递任何类型,编译时类型pcProductCategory,因此当您调用MyExtension时,T是输入ProductCategory

约束where T : IHierarchical<T>怎么样?

它表示ProductCategory应该是IHierarchical<ProductCategory>ProductCategory显然不是IHierarchical<Category>。它相当Category,因此它不会编译。

要解决此问题,您可能需要转发((Category)pc).MyExtension();

{{1}}

答案 2 :(得分:2)

T的推断类型是ProductCategory,正如编译器错误所示,这不会实现IHierarchical<ProductCategory>。您可以手动将类型指定为Category

var pc = new ProductCategory();
pc.MyExtension<Category>();

答案 3 :(得分:1)

当您将ProductCategory项目传递给MyExtension时,T被推断为ProductCategory,因此约束为ProductCategory : IHierarchical<ProductCategory>。它失败,因为ProductCategory仅实现IHierarchical<Category>

协方差意味着可以在期望IHierarchical<ProductCategory>的地方使用IHierarchical<Category>个对象。你要做的是相反的。因此,你需要 contravariance ,但这不是解决方案(如果T Parent是逆变的话,你不能拥有T属性。)

要成功使用此代码,您可以在通话中指定T

ProductCategory pc = ...;
pc.MyExtension<Category>();

这将成功,因为约束变为IHierarchical<Category> pc满足。

另一种解决方案是使用泛型接口继承的非泛型接口:

public interface IHierarchical {
    ...
}

public interface IHierarchical<out T> : IHierarchical where T : IHierarchical<T> {
    ...
}

public static string MyExtension(this IHierarchical item) {
    ...
}