在 C# 中最快访问可空类型的成员

Fastest access to member of nullable type in C#

我有一个可为空类型的字段,其值不是 null。 以下哪种方法最快:

  1. 无条件成员访问权限

    ThisCantBeNull?.SomeMember
    
  2. 强制转换为不可空

    ((MyType)ThisCantBeNull).SomeMember
    
  3. Value 可空类型成员的使用

    ThisCantBeNull.Value.SomeMember
    

请注意,这只是一个理论问题,这些细微差别并不重要,我只对语言的工作方式以及后台发生的事情感兴趣。

由于您已经在其他地方检查过 null,所以只需选择 Value,您的第三个选项。

其他两个选项包括额外检查。

但是,如评论中所述,性能改进可能很小。

出于好奇:

public struct MyType
{
    public int SomeMember { get; set; }
}

一些非常原始的测试,禁用编译器优化

MyType? thisCantBeNull = new MyType();
MyType someDefaultValue = new MyType();

var t1 = new Action(() => { var r = (thisCantBeNull ?? someDefaultValue).SomeMember; });
var t2 = new Action(() => { var r = ((MyType)thisCantBeNull).SomeMember; });
var t3 = new Action(() => { var r = thisCantBeNull.Value.SomeMember; });
var t4 = new Action(() => { var r = thisCantBeNull.GetValueOrDefault().SomeMember; });

const int times = 1000 * 1000 * 1000;

var r1 = t1.RunNTimes(times);
// Elapsed Timespan = 00:00:14.45115

var r2 = t2.RunNTimes(times);
// Elapsed Timespan = 00:00:07.9415388

var r3 = t3.RunNTimes(times);
// Elapsed Timespan = 00:00:08.0096765

var r4 = t4.RunNTimes(times);
// Elapsed Timespan = 00:00:07.4732878

相同的测试,启用编译器优化

var r1 = t1.RunNTimes(times);
// Elapsed Timespan = 00:00:02.9142143

var r2 = t2.RunNTimes(times);
// Elapsed Timespan = 00:00:02.4417182

var r3 = t3.RunNTimes(times);
// Elapsed Timespan = 00:00:02.6278304

var r4 = t4.RunNTimes(times);
// Elapsed Timespan = 00:00:02.1725020

其中 RunNTimes 是:

public static TimeSpan RunNTimes(this Action a, int nTimes = 1)
{
    if (nTimes == 0)
        throw new ArgumentException("0 times not allowed", nameof(nTimes));

    var stopwatch = new Stopwatch();

    stopwatch.Start();
    for (int i = 0; i < nTimes; ++i)
        a();
    stopwatch.Stop();

    return stopwatch.Elapsed;;
}