为什么我可以在它可能不可为空或可能不是对象的情况下测试null的泛型?

时间:2011-02-22 16:04:04

标签: c# generics

在编写包含通用变量

的类时
public class ServiceInvoker<TService> : IDisposable
{
    private TService _Service;

    public ServiceInvoker()
    {
        _Service = Activator.CreateInstance<TService>();
    }

    public void Invoke(Action<TService> action)
    {
        // CAN use null
        if (_Service == null)
            throw new ObjectDisposedException("ServiceInvoker");

        ....
    }

    public void Dispose()
    {
        // CAN'T use null
        this._Service = default(TService);
    }
}

我注意到编译器允许我检查泛型变量的null,但是,当然,不允许我将其设置为null,因此我们必须使用default(TService)

编译器不应该警告我使用null吗?或者它是否使用装箱转换到一个对象来进行null测试?

我读到proper null evaluation for generic,但我很想知道原因,而不仅仅是如何。

4 个答案:

答案 0 :(得分:12)

  

为什么我可以在null可以为空或可能不是对象的情况下测试null的泛型?

这个问题是不合适的;泛型类型的任何表达式的值在运行时将始终是对象或空引用。我想你想问:

  

为什么我可以测试null的泛型,因为它的运行时类型既不是可空值类型也不是引用类型?

C#规范保证在7.6.10节中对文字null的相等比较是合法的,为方便起见,我在这里引用:


  

如果将类型参数类型T的操作数与null进行比较,并且T的运行时类型是值类型,则比较结果为false。 [...]即使T可以表示值类型,也允许x == null构造,并且当T是值类型时,结果被简单地定义为假。


请注意,此处的规范存在一个小错误;最后一句应该以“不可为空的值类型”结束。

我不确定我是否真的回答了“为什么?”问题是否令人满意。如果这不令人满意,请尝试提出更具体的问题。

  

编译器不应该警告我使用null吗?

没有。为什么您认为编译器应该警告您正确使用该语言的功能?

  

是否使用装箱转换到一个对象来测试null?

嗯,这有点棘手。一方面,第7.6.10节规定:


  

预定义的引用类型相等运算符永远不会导致其操作数发生装箱操作。执行此类装箱操作将毫无意义,因为对新分配的盒装实例的引用必然会与所有其他引用不同。


然而,当我们生成IL以将泛型T与null进行比较时,我们当然实际上会生成一个T的框,一个null的加载和一个比较。抖动可以足够智能以消除拳击的实际内存分配;如果T是引用类型,那么它不需要装箱,如果它是可以为空的值类型,则可以将其转换为检查HasValue属性的调用,如果它是不可为空的值类型,那么装箱和检查可以是变成简单的“假”。我不确切知道各种不同的jit编译器实现到底是做什么的;如果你有兴趣,请查看!

答案 1 :(得分:4)

CLR知道不可为空的值类型永远不能为null,因此它可能总是返回false。这就是你问的问题吗?

答案 2 :(得分:1)

这会编译,但会发出警告:

int l = 0;
if (l == null) {
    //whatever
}

警告是这样的:

 warning CS0472: The result of the expression is always 'false'
 since a value of type 'int' is never equal to 'null' of type 'int?'

所以它有效,但结果不是非常有用。但是,通用,这可能是一个有用的测试。

答案 3 :(得分:1)

为什么你认为编译器应该警告你?当你使用这样的东西时,编译器会发出警告:

if (1 == 2) //always false
if (Dog is Cat) //never true

但在这种情况下,条件可能为真(当TService是refernece类型且它为null时),或者为false(当它是值类型或引用类型但不为null时)。它完美地代表了 if 语句的用法(有时是真的,有时是假的)。