2012-08-16 61 views
2

我們希望避免產生NullReferenceException。目前我們有:轉換時避免NullReferenceException的首選做法?

ISomeInterface interface = this.GetISomeInterfaceInstance(); 
(interface as ClassImplmentsISomeInterface).Method(); 

這工作正常,但風險NullReferenceException。一個解決方案是:

ISomeInterface interface = this.GetISomeInterfaceInstance(); 
ClassImplmentsISomeInterface instance = interface as ClassImplmentsISomeInterface; 
if (instance != null) 
    instance.Method(); 

但這會產生大量的額外的代碼爲一個簡單的檢查(根據ReSharper的有可能的NRE的100S)。第二溶液的方法是:

ISomeInterface interface = this.GetISomeInterfaceInstance(); 
if (interface is ClassImplmentsISomeInterface) 
    (interface as ClassImplmentsISomeInterface).Method(); 

但我知道is實際上在後臺使用了as,因此做了兩次演員,我想避免。這很重要嗎?例如,C#編譯器是否足夠聰明以優化此性能問題?

有沒有其他一些技術我在這裏失蹤?或者上述方法之一更可取?

+2

如果代碼無法調用Method()方法, '?如果答案是否定的,那麼NRE可能是最好的事情發生。 – 2012-08-16 09:19:04

+0

@Damien_The_Unbeliever在每個我們冒着NRE風險的情況下,我們可以在沒有調用Method()的情況下繼續 - 我們可以靜靜地登錄並繼續。如果不考慮這個問題,我不會問這樣一個具體的問題。 :) – 2012-08-16 10:16:42

回答

0

去。但是,您還應該考慮重構代碼,使其不再需要強制轉換。

0

如果你想投推測那麼你的第一個選項(asnull檢查)建議我通常

ISomeInterface variable = this.GetISomeInterfaceInstance(); 
var myInterface = variable as ClassImplmentsISomeInterface; 

if(myInterface != null) 
myInterface.Method(); 
+0

因此,問題中的第一種方法,但使用'var'。 – 2012-08-16 10:18:34

+0

@PreetSangha它有什麼好處?我看不到任何新東西。 – Omtara 2012-08-16 11:37:01

+0

@Omtara - 自那時起編輯。 – 2012-08-16 12:18:38

0

在某些情況下,模式NullObject可以處理它。您可以封裝投射機制並返回NullObject。但同樣,只使用它,如果它符合您的情況

Null Object pattern wiki page

0

您可以使用代理模式來模擬這種方式NullObject

class ClassImplmentsISomeInterfaceProxy:ClassImplmentsISomeInterface 
{ 
     ClassImplmentsISomeInterface target; 
     ClassImplmentsISomeInterfaceProxy(ISomeInterface actual) 
     { 
      target=actual as ClassImplmentsISomeInterface; 
     } 
     //method implementations, with check for null 
} 

但要確保你確實需要這樣的設計: amny類型檢查通常意味着有重構的東西。

4

我能想到的一個很好的方法,這將使你的代碼更短:

public static void InvokeIfIsT<T>(object o, Action<T> action) 
{ 
    if (o is T) 
     action((T)o); 
} 

使用它這樣的:

ISomeInterface interface = this.GetISomeInterfaceInstance(); 
InvokeIfIsT<ClassImplmentsISomeInterface>(interface, i => i.Method()); 
+1

好的解決方案。我寧願命名方法InvokeIfIsType或IfIsOfTypeDo – 2012-08-16 09:39:56

+0

這是一個好主意。不幸的是,我可能不會得到好處,因爲我在我的問題中使用的示例是超級簡化的。但對於任何有這種類型代碼的人來說,這將會很棒。 – 2012-08-16 10:08:43

1

我個人只使用一個!= null測試,如果我想的東西可能是空值。但如果是因爲你將一個Interface對象轉換爲一個具體的對象,那麼我認爲你必須退一步來重新評估你的設計。如果我必須將Interface對象轉換爲具體對象才能使用它,我認爲自己失敗了。

使用工廠獲取實現接口的對象,但必須將其轉換爲具體對象才能使用該對象是禁忌恕我直言。如果接口指定了一個方法,那麼你不應該關心什麼類型的對象實現接口。如果你關心方法的作用,那麼你應該創建一個不同的接口,並讓你的具體類實現它。

請記住,類可以實現儘可能多的接口,只要你喜歡。

+0

不幸的是,這個產品是古老的 - 我不能在這個階段進行任何實質性的重構。你是對的,但這是問題的根源。 – 2012-08-16 10:03:23

+0

也就是說,在一些地方這已經完成 - 但由於各種原因,在所有情況下都是不可能的。 – 2012-08-16 10:19:45

+0

你有我最深切的同情心。 – DeanOC 2012-08-16 23:13:24

1

你是正確的在is使用as如果結果不是null(反之亦然)

不過我建議你把ReSharper的規則作爲提示或指導方針,而不是規則返回一個布爾值true要遵循(我真的把它關掉),和我說,因爲沒有什麼錯一個NullReferenceException被拋出

考慮您的代碼

ISomeInterface interface = this.GetISomeInterfaceInstance(); 
(interface as ClassImplmentsISomeInterface).Method(); 
//error thrown above as null reference 

現在你繼續前進,它重構爲

ISomeInterface interface = this.GetISomeInterfaceInstance(); 
if (interface is ClassImplmentsISomeInterface) 
{ 
    (interface as ClassImplmentsISomeInterface).Method(); 
} 
else 
{ 
    //else?? else what? how do you recover? 
} 

沒有什麼錯的異常,如果一個例外就是這樣,一個異常

現在你可能會說「處理其他情形比成本更低一個例外」,但是這只是個案,如果你能恢復,例如,如果你可以寫這樣的事情

ISomeInterface interface = this.GetISomeInterfaceInstance(); 

try 
{ 
    (interface as ClassImplmentsISomeInterface).Method(); 
} 
catch (NullReferenceException) 
{ 
    interface = this.GetIOtherInterface().Method(); 
} 

那麼這將是值得重構爲一個空檢查,你實際上是做一些有用的東西。如果你的方法無法正常恢復,那麼你的方法需要拋出一個異常給它的調用者說:「嗨,出錯了」

+0

嗨Jaimal,謝謝你的迴應。在我發現的每一種情況下,我們都會(也可能應該)使用try-catch塊,就像你最後說的那樣。在任何情況下,我們都可以恢復並繼續。 – 2012-08-16 10:12:33

相關問題