泛型类中未使用的类型参数

Posted

技术标签:

【中文标题】泛型类中未使用的类型参数【英文标题】:unused type parameter in generic class 【发布时间】:2021-07-29 13:59:29 【问题描述】:

假设我有如下类:

public class Input<T>

    // some data here but type T is never directly used

    internal void Foo()
    
        object output = someOther.CreateOutput(this);
        .....
    

public class Output<T>

    public T Value  get; 
    //.....

class SomeOtherClass

    public Output<T> CreateOutput<T>(Input<T> input)
    
       // type T is used here
    

Resharper 在此处给出警告,即未使用类 Input 中的泛型类型参数 T。但是它在 Foo() 中间接使用。

我的问题是,我可以放心地忽略这个 Resharper 警告,还是这个设计有问题?基本上,我希望类 Input 的实例包含有关类型 T 的信息,以便使用 Input 的特定实例仅创建特定类型的 Output。当输出创建失败并且我可以访问 Input 实例(例如,在异常中)并且想知道创建了哪种输出时,这也可能用于诊断错误。

我想换个说法,有一个泛型类,其类型参数定义其在传递给其他类时的行为,但类型参数不用于定义此类中的任何数据,这是一种可接受的设计吗?

【问题讨论】:

但是在Foo()中是间接使用的。它是如何间接使用的? 将“this”传递给 CreateOutput() 确定用于 CreateOutput() 调用的泛型类型参数,因此不必明确指定。 【参考方案1】:

我想换个说法,有一个泛型类,其类型参数定义其在传递给其他类时的行为,但类型参数不用于定义此类中的任何数据,这是一种可接受的设计吗?

我会说这应该没问题。由于未显示 CreateOutput 方法,因此如果没有有关您的特定用例的更多详细信息,就很难判断。

我做了类似的事情来确保类型是明确的。例如,Id&lt;T&gt; 包装在 Guid 周围,以帮助确保 Id&lt;Orange&gt; 不会传递到需要 Id&lt;Apple&gt; 的方法中。

您也可以考虑将类型存储为属性而不是泛型类型参数。即

public class Input
 
     private Type myType;

这可能会使将类型转发到 CreateOutput 变得更容易,而不必使所有方法都通用,这可能有好处和坏处,具体取决于您的使用方式。

Resharper 警告很不错,但我会非常担心它们。我会更关心实际的编译器警告。

【讨论】:

我想知道,如果我将 Type myType 存储为属性,我将如何使用它调用 CreateOutput()?我必须使用反射,还是有其他我不知道的方法? @Yevgeniy P 您可以使用反射,但首选方法是CreateOutput 也采用类型参数。这将取决于用例是否合适。对于使用反射的库来说,接受类型对象的非泛型方法和带有类型参数的泛型版本是相当常见的。【参考方案2】:

你写的是一个复杂的版本:

public class Input

    internal void Foo<T>()
    
        object output = someOther.CreateOutput<T>(this);
        .....
    

public class Output<T>

    public T Value  get; 
    //.....

class SomeOtherClass

    public Output<T> CreateOutput<T>(Input input)
    
       // type T is used here
    

由于您的Input 类不包含与T 相关的任何信息,因此没有理由将其设为通用。您写的内容在技术上并非不正确,但您引入了一个人为限制,即给定输入只能是 Food 用于构造它的具体 T。人为的,因为Input 携带的数据中没有任何内容依赖于T

这很糟糕吗?不知道,你打算这样吗?如果以这种方式创建的约束你想要的,那么禁止警告。如果不是,则更改设计。这就是为什么它是一个警告,很有可能有人会在不知不觉中写下这个。

【讨论】:

感谢您的回答。不幸的是,这对我不起作用,因为调用 Foo() 的代码不知道类型 T (存在派生 Input 的类层次结构,而调用 Foo() 的代码只知道该层次结构的基类)。基本上,我似乎确实需要类型 T 以某种方式成为 Input 的一部分。

以上是关于泛型类中未使用的类型参数的主要内容,如果未能解决你的问题,请参考以下文章

17.scala的泛型类

泛型类中的数组

在 Typescript 的泛型类中初始化泛型类型

在泛型类中传递泛型参数

Java泛型

泛型学习笔记