【发布时间】:2016-10-07 10:42:57
【问题描述】:
我目前在 C# 中遇到泛型问题,我有一个解决方案,但我正在寻找一个更简洁的解决方案。我通常有很好的 C# 知识,所以我不确定我想要的是否存在。
我有一个带有嵌套约束的通用基类
public abstract class BaseParam { }
public abstract class BaseProcess<TParam> : IProcess
where TParam : BaseParam
{
public TParam Parameter { get; set; }
}
public abstract class BaseTask<TProc, TParam>
where TProc : BaseProcess<TParam>, new()
where TParam : BaseParam, new()
{
public IProcess Create()
{
var proc = new TProc();
proc.Param = new TParam();
return proc;
}
}
现在我可以创建几个派生,这工作了一段时间
public class SomeParam : BaseParam { }
public class SomeProcess : BaseProcess<SomeParam> { }
public class SomeTask : BaseTask<SomeProcess, SomeParam> { }
当我开始像这样混合继承级别时会出现问题
public class SuperParam : SomeParam { }
// The next line won't compile
public class SuperTask : BaseTask<SomeProcess, SuperParam> { }
我知道它不能编译,因为协方差只存在于接口上,Foo<A> 和Foo<B> 在技术上是两个不同的类。但是里面的代码可以正常工作。我想要的是写一个“协变约束”,如:
public abstract class BaseTask<TProc, TParam>
where TProc : BaseProcess<TProcParam>
where TProcParam : BaseParam
where TParam : TProcParam
{
}
我尝试使用ISomeProc<TParam>,因为接口是协变的,但这仅适用于分配,而不适用于下限。功能变通方法是声明一个额外的类型参数,但这还不够:
public abstract class BaseTask<TProc, TProcParam, TParam>
where TProc : BaseProcess<TProcParam>
where TProcParam : BaseParam
where TParam : TProcParam
{
}
编译器错误:
The type 'SomeProcess' cannot be used as type parameter 'TProc' in the
generic type or method 'BaseTask<TProc,TParam>'. There is no implicit
reference conversion from 'SomeProcess' to 'BaseProc<SuperParam>'.
编辑:我明白需要更多解释。在类中我不需要SuperParam 的属性,只需要BaseParam,但它应该是SuperParam 的一个实例。然而,我们通过反射阅读了SuperTask 的定义并创建了一个编辑器。并且那个编辑器必须知道它应该创建什么对象。
问题:有没有办法设计BaseTask的约束,使其尊重协方差而不添加额外的参数TProcParam?我可以想出解决方法,但我觉得有更简单的方法。
【问题讨论】:
-
您好,为了清楚起见,您也可以发布编译器错误吗?
-
“但是里面的代码可以正常工作”你怎么知道的?不看“里面的代码”很难知道。
-
好的,您尝试了一些方法,但没有成功,但我想知道您的问题是什么?
-
你的基类在
TParam中不是、不可能、永远不会是协变的,因为Parameter有一个setter。碰巧 C# 不允许类变体(在我看来,这是一个很大的疏忽),但即使它允许你也不能使它成为协变的。 -
如果你希望你的类型参数是协变的。您可以在通用接口和委托中使用 out 关键字。尝试使用@ArturoMenchaca 的方法