2009-12-11 132 views
6

以下2個代碼片段是否實現了相同的功能?這兩個陳述是否相同?

我的原代碼:

if (safeFileNames != null) 
{ 
    this.SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
} 
else 
{ 
    this.SafeFileNames = false; 
} 

什麼ReSharper的想法是一個更好的主意:

this.SafeFileNames = safeFileNames != null && 
        Convert.ToBoolean(safeFileNames.Value); 

我覺得上面的代碼更易於閱讀,任何令人信服的理由去改變它?
它會執行得更快嗎,而且最重要的是,代碼能夠完成同樣的事情嗎?

此外,如果你看看:Convert.ToBoolean(safeFileNames.Value);節,那麼肯定這可能會導致空引用異常?

this.SafeFileNames = bool 

本地safeFileNames是一個強類型的自定義對象,這裏是類:

public class Configuration 
    { 
     public string Name 
     { 
      get; 
      set; 
     } 
     public string Value 
     { 
      get; 
      set; 
     } 
    } 
+3

你不會得到一個'NullReferenceExcepton'由於第一部分的聲明'safeFileNames!= null'將會短路,你永遠不會碰到'Convert.ToBoolean(safeFileNames.Value)' - 那就是wa &&&&作品。 – Nate 2009-12-11 21:41:35

+2

由於C#的懶惰評估,它不會導致空引用異常。 &&語句總是在左側和右側進行評估。但是,如果左邊是錯誤的,那麼它就不會評估右邊,因爲邏輯結果已經確定。所以,如果safeFileNames爲null,那麼Convert.ToBoolean調用永遠不會發生。 這類事情在代碼中很常見。 – 2009-12-11 21:48:21

+1

所以如果我理解&& - 如果左邊的部分是假的,它會返回false ...否則它會評估正確的部分,並返回右邊部分的結果? – 2009-12-11 21:50:11

回答

24

你問這個問題的事實告訴我,前者是首選。也就是說,在我看來,你的問題意味着你相信第一個代碼更容易理解,而你不確定第二個代碼是否相同。軟件設計的主要目標是管理複雜性。如果您現在對此感到困惑,那麼稍後您可能會對此感到困惑,或者對於任何支持您的代碼的人來說,這可能都會對您造成困擾。

+4

這是一個很好的答案。 – jason 2009-12-11 21:45:48

+0

+1到KISS [15] – 2009-12-11 21:49:13

+0

非常好的方式來看看它。 – 2009-12-11 21:54:32

5

兩個語句做同樣的事情。哪個使用是一個偏好問題,但我更喜歡Resharper的版本。更簡潔,更少移動的部分。更容易看到代碼的意圖。

+0

如果this.SafeFileNames爲空,該怎麼辦?當然試圖對空的Convert.ToBoolean,會導致一個空引用異常? – 2009-12-11 21:39:19

+0

@JL:如果SafeFileNames爲null,則第二個子句永遠不會執行 – Randolpho 2009-12-11 21:40:25

+0

獲勝的短路。 – 2009-12-11 21:42:31

1

它們是一樣的。 & &是一個短路運算符,因此表達式的後半部分不會評估safeFileNames是否爲空。

1

它們是相同的。在單行中,如果第一個條件失敗,則第二個條件不被評估。所以你不會得到一個空引用。

我敢打賭,IL在兩種情況下都是一樣的。

我更喜歡第二個版本。

2

它通過使用resharper建議來降低代碼的圈複雜度。

是否更容易閱讀,是個人意見,但我更喜歡resharper給你的建議。

他們是相同的,如果你想可讀性,我還可以建議如下:

if (safeFileNames != null) 
    this.SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
else 
    this.SafeFileNames = false; 

this.SafeFileNames = safeFileNames != null ? Convert.ToBoolean(safeFileNames.Value) : false 
+0

注意:如果不需要大括號,可以讓代碼看起來更好,而且基於觀點。 – 2009-12-11 21:53:03

+0

@Aequtarium,你的回答不正確或效率低下。我想,這不像其他人那麼激動人心。投票你。 – 2009-12-11 22:00:28

+0

這是一個意見,但值得注意的是,StyleCop會將此標記爲錯誤。一致性是一個因素;另一個是當你在if中添加你的第二個語句(沒有別的)時,引入一個錯誤,並忘記添加你的大括號。 IDE通常會縮進並通知您,但是如果您碰巧使用了Visual Notepad .... – 2009-12-11 22:03:52

1

沒錯這兩個語句會做同樣的事情,你不不得不將重新清晰的建議作爲福音,一個人認爲是可讀的代碼是另一個男人的混亂。

還有其他一些方法可以做你想做的事,可能會更易讀,什麼樣的值類型是safeFileNames?它看起來可能是一個可空的布爾?如果是這樣,你可以簡單地寫,

this.SafeFileNames = safeFileNames.GetValueOrDefault(); 
0

從邏輯上說,它們是相同的。任何性能差異都可能會被忽略。第二種形式可能會轉化爲更有效的二進制代碼,因爲第二種形式會取消條件式。條件(不正確的推測執行)會在CPU密集型工作中混淆CPU的指令流水線。然而,IL和JITter都需要發出足夠的質量代碼才能產生很大的差異。

我同意你的可讀性,但我不認爲每個人都會這樣認爲。

5

這是兩個代碼段的IL。我把你的代碼和創建一個控制檯應用程序來看看IL。正如你從結果IL中看到的,一個方法(方法2)縮短了4個字節,但爲兩者運行的IL幾乎相同,所以就性能而言......不用擔心這一點。他們都會有相同的表現。更多地關注哪一個更容易閱讀,並更好地展示你的意圖。

我的代碼:

class Program 
{ 
    static void Main(string[] args) 
    { 


    } 
    public void method1() 
    { 
     bool? safeFileNames = null; 

     if (safeFileNames != null) 
     { 
      SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
     } 
     else 
     { 
      SafeFileNames = false; 
     } 
    } 
    public void method2() 
    { 
     bool? safeFileNames = null; 
     SafeFileNames = safeFileNames != null && Convert.ToBoolean(safeFileNames.Value); 
    } 
    public static bool SafeFileNames { get; set; } 
} 

的IL的方法1:

.method public hidebysig instance void method1() cil managed 
{ 
    // Code size  42 (0x2a) 
    .maxstack 1 
    .locals init ([0] valuetype [mscorlib]System.Nullable`1<bool> safeFileNames) 
    IL_0000: ldloca.s safeFileNames 
    IL_0002: initobj valuetype [mscorlib]System.Nullable`1<bool> 
    IL_0008: ldloca.s safeFileNames 
    IL_000a: call  instance bool valuetype [mscorlib]System.Nullable`1<bool>::get_HasValue() 
    IL_000f: brfalse.s IL_0023 
    IL_0011: ldloca.s safeFileNames 
    IL_0013: call  instance !0 valuetype [mscorlib]System.Nullable`1<bool>::get_Value() 
    IL_0018: call  bool [mscorlib]System.Convert::ToBoolean(bool) 
    IL_001d: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0022: ret 
    IL_0023: ldc.i4.0 
    IL_0024: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0029: ret 
} // end of method Program::method1 

的IL的方法2:

.method public hidebysig instance void method2() cil managed 
{ 
    // Code size  38 (0x26) 
    .maxstack 1 
    .locals init ([0] valuetype [mscorlib]System.Nullable`1<bool> safeFileNames) 
    IL_0000: ldloca.s safeFileNames 
    IL_0002: initobj valuetype [mscorlib]System.Nullable`1<bool> 
    IL_0008: ldloca.s safeFileNames 
    IL_000a: call  instance bool valuetype [mscorlib]System.Nullable`1<bool>::get_HasValue() 
    IL_000f: brfalse.s IL_001f 
    IL_0011: ldloca.s safeFileNames 
    IL_0013: call  instance !0 valuetype [mscorlib]System.Nullable`1<bool>::get_Value() 
    IL_0018: call  bool [mscorlib]System.Convert::ToBoolean(bool) 
    IL_001d: br.s  IL_0020 
    IL_001f: ldc.i4.0 
    IL_0020: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0025: ret 
} // end of method Program::method2 
+1

如果我可以給出這個超過1分的話,我會愛人們檢查IL以確定實際差異。 – 2009-12-11 21:58:15

+0

+1付出極大的努力,非常感謝! – 2009-12-11 22:03:20

+0

看起來像一個很好的藉口,撣掉ildasm並玩了一會兒:-) – jvilalta 2009-12-11 22:03:45