[英]Correct evaluation of expression
我在別人的代碼中遇到了以下表達式。 我認為這是很糟糕的代碼,其原因有很多(特別是因為它沒有考慮到bool.TrueString和bool.FalseString),但對於編譯器如何評估它感到好奇。
private bool GetBoolValue(string value)
{
return value != null ? value.ToUpper() == "ON" ? true : false : false;
}
編輯順便說一下,不是從內向外評估的表情? 在這種情況下,在對value.ToUpper()的調用之后檢查value!= null的意義何在?它將拋出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";
這是對表達式的正確重寫嗎?
看來該方法旨在處理來自checkbox
HTML元素的值。 如果未為復選框指定任何值,則默認情況下它將使用值"on"
。 如果未選中此復選框,則表單數據中根本沒有任何值,因此從Request.Form
讀取鍵將提供空引用。
在這種情況下,該方法是正確的,盡管由於使用if-condition-then-true-else-false
反模式而非常可怕。 同樣,應該給它一個更適合其特定用途的名稱,例如GetCheckboxValue
。
您對該方法的重寫是正確無誤的。 由於該值不依賴於區域性,因此將值轉換為大寫不應使用當前的區域性。 因此,一個比您建議的重寫甚至更好的重寫將是:
return value != null && value.ToUpperInvariant == "ON";
(與文化無關的方法也比使用特定文化的方法要快一些,因此沒有理由不使用它們。)
順便說一句,不是從內到外對表達式求值嗎?
如果是方法調用,以便實際上對所有表達式進行求值,則必須進行內部調用,以評估外部調用的參數。
但是,僅在使用條件表達式的第二和第三操作數的情況下才對其求值,因此從外部和內部對表達式進行求值。 首先評估最外面的條件,以決定將評估哪個操作數。
無論是在重寫還是斷言這種簡潔的做法都是不好的,因為它會導致混亂,您是正確的。
好,第一個是雙嵌套三元運算符
return (value != null) ? [[[value.ToUpper() == "ON" ? true : false]]] : false;
[[[]]]中的位是三進制表達式的第一個結果,當第一個條件為true時將對其求值,因此您在讀/斷言它是正確的
但其丑陋如地獄,在當前狀態下非常難以讀取/無法維護。 我一定會將其更改為您的最后建議
邊注:
做的人
if(X == true)
return true;
else
return false;
代替
return X;
應該拿出來開槍;-)
您在尋找速度或可讀性和組織性嗎? 執行速度快,示例簡短,可能是最好的選擇。
再花幾毫秒的時間,您可以像下面這樣重新編寫此實用程序方法作為擴展方法:
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();
}
編輯:實際上,我錯了...快速性能測試表明,擴展方法比內聯方法更快 。 下面是我的測試源以及PC上的輸出。
[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
我閱讀原始表達的方式與您相同。 因此,我認為您的簡短表達是正確的。 如果value為null,它將永遠不會達到第二個條件,因此對我來說看起來很安全。
我也討厭這樣的構造:
if (value.ToUpper() == "ON")
{
return true;
}
else // this else is actually pointless
{
return false;
}
如您所見,這是一種漫長而復雜的(更不用說愚蠢的)寫作方式:
return value.ToUpper() == "ON";
您的主張很好,簡短而正確。
另一種選擇:
return string.Equals( value, "ON", StringComparison.OrdinalIgnoreCase );
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.