【问题标题】:Generic type specified by inherits由继承指定的泛型类型
【发布时间】:2018-05-22 11:26:12
【问题描述】:

我不认为我想要的东西是可能的,但我希望有人可以验证这一点并解释为什么它是不可能的。

我们有Bar<T>的继承,我们不能接触Bar<T>的源代码

abstract class Foo<T> : Bar<T>

我们提供Foo&lt;T&gt; 由第三方实现,并且我们还希望规定从Foo&lt;T&gt; 继承的任何类都是T 的指定类型。 这当然可以由第三方手动完成,例如

class Fizz : Foo<Fizz>

但是,我发现Fizz 的重复既麻烦又丑陋。 是否可以让Foo&lt;T&gt; 自动使用Fizz 作为T 的指定类型? 换句话说,是否有可能让Foo&lt;T&gt; 按照这些思路实现一些东西

abstract class Foo : Bar<T>
    where T : "Whatever class inherits from Foo"

... 我不相信这是可能的,因为我找不到合适的泛型类型约束。 是否可以改为这样做

[SomeBlackMagic("Dear compiler, T is whatever inherits from Foo.")]
abstract class Foo : Bar<T>

... 这样Fizz 的实现就可以简单地是

class Fizz : Foo

【问题讨论】:

  • 不,这在默认情况下是不可能的,但看起来您正在交付一个库,您可以包含一些 Roslyn 构建步骤来为您执行此操作。
  • 这将是一个可行的选择。我以前没有使用过 Roslyn - 你对如何开始使用 Roslyn 解决这个问题有什么建议吗?

标签: c# generics inheritance


【解决方案1】:

这就是所谓的Curiously Recurring Template Pattern。不幸的是,大多数强类型语言都无法消除这种代码异味。 C# 无法对此进行改进。

您可以诉诸运行时检查,但代价是编译时检查。此外,您实际上不会在类接口中使用该类型。例如,您将无法执行abstract class Foo&lt;T&gt; { public T Bar() { ... } } 之类的操作,因为编译器不会知道T

【讨论】:

    【解决方案2】:

    这可能不是您想要的,但您是否考虑过在Foo&lt;T&gt; 上实现一个接口,以便您始终可以确定通用T 的类型是什么?

    public class Bar<T>
    {}
    
    public interface IDev
    {}
    
    public abstract class Foo<T> : Bar<T> where T : IDev
    {}
    
    public class Fizz : Foo<Fizz>, IDev
    {}
    

    它可以让你对传入的通用对象进行一些控制。

    【讨论】:

    • 是的,这也是我在实际实现中所做的,它用于指示 Fizz 必须是 IDev。遗憾的是,这并没有消除 Fizz : Foo&lt;Fizz&gt; 重复。
    • 我有点猜想你会在我提交后准备好一些东西。抱歉,我无法提供更多帮助。
    【解决方案3】:

    我们还想规定从 Foo 继承的任何类都是 T 的指定类型。

    此要求可以作为自定义 Roslyn 分析器来实现。

    虽然这块abstract class Foo : Bar&lt;T&gt; 很遗憾是不可能的,因为T 泛型参数应该被某种类型关闭,或者Foo 也必须是泛型的。

    【讨论】:

      【解决方案4】:
      abstract class Foo<T> : Bar<T>
          where T : Foo<T>
      { /* ... */ }
      
      class Fizz : Foo<Fizz>
      { /* ... */ }
      

      我知道这不是您想要的,但它是最佳选择。

      【讨论】:

        猜你喜欢
        • 2018-09-27
        • 2015-09-15
        • 2018-08-01
        • 2021-10-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-19
        相关资源
        最近更新 更多