[英]C# Type Erasure Issues
在C#中组合状态机。 我有一个接口和抽象实现类为:
public interface IState<SD> where SD : IStateData {
T EnterState<T>(InputData inputData, SD movementData) where T : IState<SD>;
}
public abstract class AMovementState : IState<MovementData> {
public abstract AMovementState EnterState<AMovementState>(InputData inputData, MovementData movementData);
}
MovementData
实现了IStateData
因此看起来应该可以正常工作。 但是我得到了编译错误:
错误CS0425:
AMovementState' of method
AMovementState.EnterState(InputData,MovementData)'的类型参数AMovementState' of method
的约束必须与T' of interface method
IState.EnterState(InputData,MovementData)'的类型参数T' of interface method
的约束匹配。 考虑改用显式接口实现(CS0425)(Assembly-CSharp)
我认为这是类型擦除的问题,但我不是100%。 我需要重新设计方法还是缺少一些愚蠢的东西? 主要来自Java背景。
我认为这是类型擦除的问题
C#没有类型擦除。 C#的实际泛型类型深入运行时。
首先,您犯了一个常见错误; 您这样做:
class C {
C M<C>() { ... }
哦,好痛 这很难读 。 方法中的C是方法声明的C,而不是类声明的C。 您做了同样的事情:
public abstract class AMovementState : IState<MovementData> {
public abstract AMovementState EnterState<AMovementState>(
InputData inputData, MovementData movementData);
}
这里也是一样。 您已经声明了两件事,都称为AMovementState
,一类是类类型,一类是类型参数。 请不要那样做。 对于代码阅读者来说,这是令人难以置信的误导。
其次,一旦解决了这个问题:C#要求实现接口方法的泛型方法与该接口方法的约束完全匹配。
现在,您可能会注意到,在这种特殊情况下,并没有逻辑要求实现方法具有约束。 可以设计类型系统,以便在这种情况下,通过类进行调用会产生较小的约束,而通过接口进行调用会产生较大的约束,这将是类型安全的。
但是C#并不是那样设计的。 它的设计要求约束必须匹配,即使在严格说来不是必须的情况下也是如此。
因此,您有两种选择:
那是:
public abstract class AMovementState : IState<MovementData> {
public abstract M EnterState<M>
(InputData inputData, MovementData movementData)
where M : IState<MovementData>;
}
要么
public abstract class AMovementState : IState<MovementData> {
public abstract M EnterState<M>
(InputData inputData, MovementData movementData);
M IState<MovementData>.EnterState<M>
(InputData inputData, MovementData movementData)
{
this.EnterState<M>(inputData, movementData);
}
}
具有讽刺意味的是,C#不允许在显式接口方法上重复约束。 它会自动推断出它们。 我一直认为这是C#最奇怪的功能之一。
更笼统地说:您可能患有通用幸福症 ,这是使事物通用的愿望,尽管这是不必要且难以理解的。 问问自己是否真的需要通用的东西。 泛型可能很难推理。 也许可以使用一个更简单的抽象。
您的类不会实现该接口,而只会实现一种特定情况。
您需要以一般方式复制该方法:
public abstract class AMovementState : IState<MovementData> {
public abstract T EnterState<T>(InputData inputData, MovementData movementData) where T : IState<MovementData>;
}
原因很简单:如果某些代码持有对IState<MovementData>
的引用,则它们将通用地调用EnterState
方法,因此实现也必须是通用的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.