泛型类型与其默认值的比较(没有泛型类约束)会产生编译时错误

JJo*_*oos 8 .net c# generics .net-3.5

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

public class Test<TDataSource>
{
    public IQueryable<TDataSource> DataSource { get; set; }

    public bool GetOneOrDefaultResult()
    {
        var result = DataSource.SingleOrDefault();
        return result != default(TDataSource);
    }
}
Run Code Online (Sandbox Code Playgroud)

你会在第8行得到一个错误("运算符'=='不能应用于'TDataSource'和'TDataSource'类型的操作数.").我认为使用default关键字将消除引用类型和值类型之间的任何比较问题.

添加将TDataSource限制为引用类型的通用约束使得这段代码可以编译.

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

这是相关的: 不能将operator ==应用于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));
    }
}
Run Code Online (Sandbox Code Playgroud)

这个编译会正常吗?

SLa*_*aks 6

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

相反,你应该写

    return !(ReferenceEquals((object)result, (object)default(TDataSource)) 
          || result.Equals(default(TDataSource)));
Run Code Online (Sandbox Code Playgroud)

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

  • 不需要那么复杂的东西,你只需要使用静态的Object.Equals方法:`Equals(result,default(TDataSource))`. (4认同)