理论上对 C# 中可为 null 类型的成员的最快访问是什么?



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

  1. 空条件成员访问

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

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

    ThisCantBeNull.Value.SomeMember
    

请注意,这只是一个理论问题,这种微小的差异无关紧要,我只对语言的工作原理和后台发生的事情感兴趣。

只是出于好奇:

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;;
}

由于您已经在其他地方检查了 null,只需获取Value,您的第三个选项。

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

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

相关内容

  • 没有找到相关文章