2017-06-06 35 views
-3

我有一个字段或可空类型,比如财产,成员访问空检查(C#)

MyType? ThisCantBeNull = Something(); 

MyType是一个结构在这里。)某处在我的代码,我保证这个东西不是null ,像这样:

if (ThisCantBeNull == null) 
    throw new Exception();//nothing special 

然后,我要访问此MyType实例的成员。我有3个选项,我的问题是,这是最好的解决方案。

  1. 空,合并运算

    ThisCantBeNull?.SomeMember ?? someDefaultValue 
    

    (ThisCantBeNull ?? someDefaultValue).SomeMember 
    
  2. 演员到非空的

    ((MyType)ThisCantBeNull).SomeMember 
    
  3. 使用NUL的Value财产拉布勒类型

    ThisCantBeNull.Value.SomeMember 
    

我不关心代码的可读性在这里,我不感兴趣的优点和来自这方面的上述技术缺陷。 我很感兴趣性能

感谢您的任何想法和信息!

+2

你不会得到比的性能微秒多出了不同的无效的检查方法。这是一种微观优化。 –

+1

https://ericlippert.com/2012/12/17/performance-rant/ –

+0

你没有考虑检查'HasValue'。顺便说一句,编译器不会优化这些吗? - 另请注意,Sematics不匹配。有一个默认值,并有一个异常是不一样的。 – Theraot

回答

0

由于您已经在其他地方检查过空,只需要获得第三个选项Value

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

但是,正如评论中指出的那样,性能改进可能是最小的。

0

只是出于好奇:

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