以下两个代码段是否实现相同的目标?
我的原始代码:
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;
}
}
答案 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都需要发出足够质量的代码才能产生很大的不同。
我同意你的可读性,但我不认为每个人都有同感。