繁体   English   中英

C#类型擦除问题

[英]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#并不是那样设计的。 它的设计要求约束必须匹配,即使在严格说来不是必须的情况下也是如此。

因此,您有两种选择:

  • 将约束添加到抽象方法,或
  • 执行错误消息中所说的内容。 创建一个调用class方法的显式接口方法。

那是:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM