这两个陈述是否相同?

时间:2009-12-11 21:36:04

标签: c# if-statement

以下两个代码段是否实现相同的目标?

我的原始代码:

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

8 个答案:

答案 0 :(得分:24)

你问这个问题的事实告诉我,前者是首选。也就是说,在我看来,你的问题意味着你相信第一个代码更容易理解,而你不确定第二个代码是否相同。软件设计的主要目标是管理复杂性。如果它现在让你感到困惑,也可能是你以后或者任何支持你的代码的人。

答案 1 :(得分:5)

这两个陈述完全相同。使用哪个是优先考虑的问题,但我更喜欢Resharper的版本。更简洁,移动部件更少。更容易看到代码的意图。

答案 2 :(得分:5)

这两段代码都是IL。我拿了你的代码并创建了一个控制台应用程序来查看IL。从结果IL可以看出,一个方法(method2)缩短了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; }
}

方法1的IL:

.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

方法2的IL:

.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

答案 3 :(得分: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

答案 4 :(得分:1)

他们是一样的。和&amp;&amp;是一个短路运算符,因此表达式的后半部分不会评估safeFileNames是否为空。

答案 5 :(得分:1)

他们是一样的。在单行中,如果第一个条件失败,则不评估第二个条件。所以你没有得到一个空引用。

我敢打赌在两种情况下IL都是相同的。

我更喜欢第二个版本。

答案 6 :(得分:1)

是的,这两个陈述都会做同样的事情,你不必把重新锐化的建议作为福音,一个人认为是可读代码是另一个人的混乱。

还有一些其他方法可以做你想做的事情,可能更具可读性,什么价值类型是safeFileNames?看起来它可能是一个可以冒犯的bool?如果是这样,你可以简单地写一下,

this.SafeFileNames = safeFileNames.GetValueOrDefault();

答案 7 :(得分:0)

逻辑上,它们是完全相同的。任何性能差异都可能是微不足道的。第二种形式可能会在某些平台上转换为更高效的二进制代码,因为第二种形式会消除条件。条件(不正确的推测执行)会在CPU密集型工作中弄乱CPU的指令管道。但是,IL和JITter都需要发出足够质量的代码才能产生很大的不同。

我同意你的可读性,但我不认为每个人都有同感。