2

让我们考虑以下类定义:

public class MyClass<T>
{
    public T t;
    public bool? c1(T obj) => obj?.Equals(null);
    public bool? c2() => t?.Equals(null);
}

毕竟,一些注释:

  • MyClass<T>不要对T类型施加任何限制 - 所以,T可以是 aclass或 a struct
  • c2() == c1(t)必须始终正确。
  • 我使用http://tryroslyn.azurewebsites.net/网站编译一些代码片段,看看 Roslyn 发出了什么。

现在,让我们分析一下 Roslyn 是如何编译的MyClass<T>

1.) c1(T)案例:

没想到,通过 Roslyn 编译器验证生成的代码后,我们可以看到以下内容:

public bool? c1(T obj)
{
    return obj != null ? new bool?(obj.Equals(null)) : null;
}

2.) c2()案例:

我期望的是与 c1(T) 相同的代码。但是,我看到的是:

public unsafe bool? c2()
{
    T* arg_33_0 = ref this.t;
    T t = default(T);
    bool? arg_43_0;
    if (t == null)
    {
        t = this.t;
        arg_33_0 = ref t;
        if (t == null)
        {
            arg_43_0 = null;
            return arg_43_0;
        }
    }
    arg_43_0 = new bool?(arg_33_0.Equals(null));
    return arg_43_0;
}

哇,为什么会发出所有不必要的代码?在发布编译模式下,我们可以看到C1 的代码大小为 39 字节,而C2 方法的代码大小为 68 字节。这是可以优化的东西吗?

4

1 回答 1

4

对于这种情况, c1CIL 代码是错误的c2

在该c1版本中,Equals会调用obj. 在该版本中,调用时c2必须格外小心,而不是复制. 那是因为它可能是一个值类型,它已被重写以修改其自己的实例数据。由于您正在调用,因此修改应该在 中可见。EqualsttTEqualsEqualstt

优化是可能的,c1 只是因为在方法返回后任何人都无法检查,所以它或它的副本是否可能被修改obj并不重要。objobj

于 2016-06-12T21:40:43.653 回答