在没有泛型类约束的情况下,将泛型类型与其默认值进行比较,会产生编译时错误

Posted

技术标签:

【中文标题】在没有泛型类约束的情况下,将泛型类型与其默认值进行比较,会产生编译时错误【英文标题】:Comparison of a generic type with its default value, without a generic class constraint, gives a compile time error 【发布时间】:2011-04-07 20:44:03 【问题描述】:

我刚遇到这种情况,我认为这是使用默认关键字的好机会。但它没有编译,我想不出为什么。下面的例子说明了我的问题:

public class Test<TDataSource>

    public IQueryable<TDataSource> DataSource  get; set; 

    public bool GetOneOrDefaultResult()
    
        var result = DataSource.SingleOrDefault();
        return result != default(TDataSource);
    

您将在第 8 行收到错误消息(“运算符 '==' 不能应用于类型为 'TDataSource' 和 'TDataSource' 的操作数。”)。我认为使用 default 关键字可以消除引用类型和值类型之间的任何比较问题。

添加一个将 TDataSource 限制为引用类型的通用约束可以编译这段代码。

有人可以解释为什么编译器不会为我解决这个问题吗?难道只是不够聪明,看不到这会起作用吗?

这是相关的: Can't operator == be applied to generic types in C#?

[编辑] SLaks 的回答给了我一些启发,'==' 运算符不起作用,但 Equals 函数应该。

    public class Test<TDataSource>

    public IQueryable<TDataSource> DataSource  get; set; 

    public bool GetOneOrDefaultResult()
    
        var result = DataSource.SingleOrDefault();
        return result.Equals(default(TDataSource));
    

这样编译能正确运行吗?

【问题讨论】:

如果你只是想弄清楚是否有结果,那你就错了,因为你无法区分没有结果和结果为 0。 Gabe函数的逻辑只是一个例子,没有用处。 您的编辑可能会引发 NullReferenceExeption。您需要调用静态的Equals(a, b) 方法。 Null or default comparison of generic argument in C#的可能重复 【参考方案1】:

您不能假设每种值类型都会覆盖== 运算符。 (即使他们这样做了,也无法使用泛型来调用它;这是一个静态方法)

相反,你应该写

    return !(ReferenceEquals((object)result, (object)default(TDataSource)) 
          || result.Equals(default(TDataSource)));

如果resultnull(和引用类型),则ReferenceEquals 调用将返回true,因此Equals 不会被调用,也不会抛出NullReferenceException。 如果TDataSource 是一个值类型,ReferenceEquals 将比较两个不同的加框引用(可能恰好包含相同的值,但仍然不同),因此它将传递给Equals 调用。

【讨论】:

请注意,一般来说,这是您必须比较两个未知类型的值是否相等的方法。 (即这不仅仅适用于查找默认值) 你说得对。这只是不覆盖“==”运算符的用户定义结构吗? @JJoos,如果值类型覆盖 == 运算符,则认为最佳做法是覆盖 Equals() 以使其行为相同。这不是严格保证的,但如果我发现一个不以这种方式运行的值类型,我会认为这是一个错误。 不需要这么复杂的东西,你只需要使用静态 Object.Equals 方法:Equals(result, default(TDataSource)) @Thomas Levesque,是的,在@SLaks 发帖后也想到了这一点。似乎工作正常并且更具可读性。

以上是关于在没有泛型类约束的情况下,将泛型类型与其默认值进行比较,会产生编译时错误的主要内容,如果未能解决你的问题,请参考以下文章

仅适用于数值类型的泛型类型约束

Kotlin泛型总结 ★ ( 泛型类 | 泛型参数 | 泛型函数 | 多泛型参数 | 泛型类型约束 | 可变参数结合泛型 | out 协变 | in 逆变 | reified 检查泛型参数类型 )

将泛型类扩展为静态内部类

将泛型值推送到 Typescript 中泛型类中的泛型列表

泛型(第四部分)

泛型类的可选方法参数的类型