将状态机放在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);
}
Run Code Online (Sandbox Code Playgroud)
MovementData实现IStateData所以这似乎应该工作正常.但是我收到了编译错误:
错误CS0425:类型参数
AMovementState' of methodAMovementState.EnterState(InputData,MovementData)'的约束必须与类型参数IState.EnterState(InputData,MovementData)'的约束匹配T' of interface method.考虑使用显式接口实现(CS0425)(Assembly-CSharp)
我认为这是类型擦除的问题,但我不是100%.我需要修改我的方法还是我错过了一些愚蠢的东西?来自大多数Java背景.
我认为这是类型擦除的问题
C#没有类型擦除.C#具有深深烘焙到运行时的实际泛型类型.
首先,你犯了一个常见的错误; 你这样做了:
class C {
C M<C>() { ... }
Run Code Online (Sandbox Code Playgroud)
哦痛苦.这很难读.方法中的C是方法声明的C,而不是类声明的C. 你做了同样的事情:
public abstract class AMovementState : IState<MovementData> {
public abstract AMovementState EnterState<AMovementState>(
InputData inputData, MovementData movementData);
}
Run Code Online (Sandbox Code Playgroud)
这里也是一样的.你已经声明了两个东西,包括AMovementState一个类类型和一个类型参数.请不要这样做.这对代码的读者来说是非常误导的.
其次,一旦解决了这个问题:C#要求实现接口方法的泛型方法完全匹配该接口方法的约束.
现在,您可能会注意到,在这种特殊情况下,没有逻辑要求实现方法具有约束.类型系统可以设计成在这种情况下,通过类调用给出一个较小的约束,并通过接口调用给出一个更大的约束,这将是类型安全的.
但C#不是那样设计的; 它的设计使得需要约束来匹配,即使在严格说来不必要的情况下也是如此.
所以,你有两个选择:
那是:
public abstract class AMovementState : IState<MovementData> {
public abstract M EnterState<M>
(InputData inputData, MovementData movementData)
where M : IState<MovementData>;
}
Run Code Online (Sandbox Code Playgroud)
要么
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);
}
}
Run Code Online (Sandbox Code Playgroud)
具有讽刺意味的是,C#不允许在显式接口方法上重复约束; 它会自动推断出来.我一直认为这是C#最奇怪的功能之一.
更一般地说:你可能患有通用性幸福病,即使它不必要且难以理解,也希望将事物变得通用.问问自己一件事物是否真的需要通用.泛型可能很难推理; 也许你可以使用更简单的抽象.