2017-06-06 71 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;; 
}