我在其他人的代码中遇到了以下表达式。我认为这是一个很糟糕的代码有很多原因(尤其是因为它没有考虑到bool.TrueString和bool.FalseString),但我很好奇编译器将如何评估它。
private bool GetBoolValue(string value)
{
return value != null ? value.ToUpper() == "ON" ? true : false : false;
}
修改 顺便说一下,不是从内向外评估的表达式吗?在这种情况下,在调用value.ToUpper()之后检查值是什么意思!= null会抛出空引用异常?
我认为以下是一个正确(故意)冗长的版本(我永远不会这样说:D):
if (value != null)
{
if (value.ToUpper() == "ON")
{
return true;
}
else // this else is actually pointless
{
return false;
}
}
else
{
return false;
}
可以缩短为:
return value != null && value.ToUpper == "ON";
这是对表达式的正确重写吗?
答案 0 :(得分:4)
看起来该方法被用来处理来自checkbox
HTML元素的值。如果没有为复选框指定值,则默认情况下使用值"on"
。如果未选中该复选框,则表单数据中没有任何值,因此从Request.Form
读取密钥会给出空引用。
在这种情况下,该方法是正确的,但由于使用了if-condition-then-true-else-false
反模式,因此它非常可怕。此外,它应该被赋予更适合其特定用途的名称,例如GetCheckboxValue
。
您重写的方法是正确和合理的。由于该值不依赖于文化,因此将值转换为大写不应使用当前文化。因此,重写甚至比您提议的重写要好一些:
return value != null && value.ToUpperInvariant == "ON";
(与文化无关的方法也比使用特定文化的方法快一点,因此没有理由不使用它们。)
顺便说一下,不是表达方式 从内向外评估?
如果是方法调用以便实际评估所有表达式,则必须进行内部调用以评估外部调用的参数。
但是,条件表达式的第二个和第三个操作数仅在使用它们时才会被计算,因此表达式将从外部和内部进行计算。首先评估最外层条件,以决定它将评估哪个操作数。
答案 1 :(得分:3)
你是正确的,无论是在你的改写还是你的断言中,这种简洁的尝试都是不好的,因为它会导致混乱。
答案 2 :(得分:2)
第一个是双嵌套三元运算符
return (value != null) ? [[[value.ToUpper() == "ON" ? true : false]]] : false;
[[[]]中的位是得到评估的三元表达式的第一个结果 当第一个条件为真时,你正在阅读/断言它是正确的
但它的丑陋如同在当前状态下非常难以理解/无法维持。 我肯定会把它改成你的最后一个建议
旁注:
做过的人
if(X == true)
return true;
else
return false;
而不是
return X;
应该被取出并拍摄; - )
答案 3 :(得分:1)
您在寻找速度,可读性和组织吗?执行速度,缩短的例子可能是最好的方法。
再过几毫秒,您可以将此实用程序方法重写为扩展方法,如下所示:
public static bool ToBoolean(this string value)
{
// Exit now if no value is set
if (string.IsNullOrEmpty(value)) return false;
switch (value.ToUpperInvariant())
{
case "ON":
case "TRUE":
return true;
}
return false;
}
...然后你会按如下方式使用它:
public static void TestMethod()
{
bool s = "Test".ToBoolean();
}
编辑: 实际上,我错了......快速的性能测试表明扩展方法比内联方法更快。我的测试来源如下,以及我电脑上的输出。
[Test]
public void Perf()
{
var testValues = new string[] {"true", "On", "test", "FaLsE", "Bogus", ""};
var rdm = new Random();
int RunCount = 100000;
bool b;
string s;
Stopwatch sw = Stopwatch.StartNew();
for (var i=0; i<RunCount; i++)
{
s = testValues[rdm.Next(0, testValues.Length - 1)];
b = s.ToBoolean();
}
Console.Out.WriteLine("Method 1: {0}ms", sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
for (var i = 0; i < RunCount; i++)
{
s = testValues[rdm.Next(0, testValues.Length - 1)];
b = s != null ? s.ToUpperInvariant() == "ON" ? true : s.ToUpperInvariant() == "TRUE" ? true : false : false;
}
Console.Out.WriteLine("Method 2: {0}ms", sw.ElapsedMilliseconds);
}
输出:
Method 1: 21ms
Method 2: 30ms
答案 4 :(得分:0)
我以同样的方式阅读原始表达。所以我认为你缩短的表达是正确的。如果value为null,它将永远不会达到第二个条件,所以对我来说看起来很安全。
答案 5 :(得分:0)
我也讨厌像
这样的结构if (value.ToUpper() == "ON")
{
return true;
}
else // this else is actually pointless
{
return false;
}
正如您所注意到的那样,这是一种漫长而复杂的(并非愚蠢的)写作方式:
return value.ToUpper() == "ON";
你的命题很好,简短而正确。
答案 6 :(得分:0)
另一种选择:
return string.Equals( value, "ON", StringComparison.OrdinalIgnoreCase );