代码之家  ›  专栏  ›  技术社区  ›  JL. Hans Passant

这两种说法相同吗?

  •  6
  • JL. Hans Passant  · 技术社区  · 15 年前

    以下两个代码片段实现了相同的功能吗?

    我的原始代码:

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

    雷斯哈珀的想法更好:

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

    我认为上面的代码更容易阅读,有什么令人信服的理由来改变它吗?
    它的执行速度会更快吗?最重要的是,代码会做完全相同的事情吗?

    另外,如果您查看: Convert.ToBoolean(safeFileNames.Value); 那么这肯定会导致空引用异常吗?

    this.SafeFileNames = bool
    

    本地安全文件名是一个强类型自定义对象,下面是类:

    public class Configuration
        {
            public string Name
            {
                get;
                set;
            }
            public string Value
            {
                get;
                set;
            }
        }
    
    8 回复  |  直到 10 年前
        1
  •  24
  •   Dave Mateer    15 年前

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

        2
  •  5
  •   Brian Frantz    15 年前

    这两种说法的作用完全相同。这是一个优先事项,但我更喜欢Resharper的版本。更简洁,运动部件更少。更容易看到代码的意图。

        3
  •  5
  •   jvilalta    15 年前

    这是两段代码的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
    
        4
  •  2
  •   Brett Allen    15 年前

    它通过使用resharper建议来降低代码的循环复杂性。

    不管它是否容易阅读,都是个人意见,不过我更喜欢雷斯哈珀给你的建议。

    它们是相同的,如果您想要可读性,我也可以建议如下:

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

    this.SafeFileNames = safeFileNames != null ? Convert.ToBoolean(safeFileNames.Value) : false
    
        5
  •  1
  •   Mark Byers    15 年前

    它们是一样的。&是一个短路运算符,因此表达式的后半部分将不会计算safefilename是否为空。

        6
  •  1
  •   nickd    15 年前

    它们是一样的。在一个衬板中,如果第一个条件失败,则不会对第二个条件进行评估。所以您不会得到空引用。

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

    我更喜欢第二个版本。

        7
  •  1
  •   mattdlong    15 年前

    是的,这两种说法都会做同样的事情,你不必把更尖锐的建议当作福音,一个人认为可读的代码是另一个人的烂摊子。

    还有一些其他的方法可以让你更容易阅读,safefilename是什么值类型?看起来它可能是一个可以为空的bool?如果是这样的话,你只需写,

    this.SafeFileNames = safeFileNames.GetValueOrDefault();
    
        8
  •  0
  •   George Spofford    15 年前

    从逻辑上讲,它们是相同的。任何性能差异都可能是不可消除的。在某些平台上,第二个表单可能会转换为更有效的二进制代码,因为第二个表单不使用条件。条件(不正确的推测性执行)会在CPU密集型工作中扰乱CPU的指令管道。然而,IL和抖动都需要发出足够质量的代码,以便产生很大的差异。

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