[英]String Compare where null and empty are equal
使用 C# 和 .NET 3.5,處理這種情況的最佳方法是什么。 我有數百個字段可以從各種來源(主要是字符串)進行比較。 有時源將字符串字段返回為空,有時返回為空。 當然,有時字段中會有文本。 例如,我目前對 strA != strB 的比較並沒有削減它,因為 strA 為空而 strB 為“”。 我知道我可以做 string.IsNullOrEmpty 這會導致雙重比較和一些丑陋。 有沒有更好的方法來處理這個問題? 我想到了擴展方法,但你不能擴展操作符。
我想我正在尋找一種性感的方式來做到這一點。
不會消除額外的潛在比較,但對於性感因素,您可以使用以下內容:
(strA ?? "") == (strB ?? "")
或者稍微不那么性感但更可取的形式:
(strA ?? string.Empty) == (strB ?? string.Empty)
由於您要進行數百次比較,聽起來您想要調用單個函數,以便減少代碼中的混亂和重復。 我不認為有一個內置函數可以將空/空字符串/比較檢查合二為一,但您可以自己制作一個:
static class Comparison
{
public static bool AreEqual(string a, string b)
{
if (string.IsNullOrEmpty(a))
{
return string.IsNullOrEmpty(b);
}
else
{
return string.Equals(a, b);
}
}
}
然后,您可以在每次比較時對您的函數進行一次調用:
if(Comparison.AreEqual(strA[0], strB[0])) { // ... }
if(Comparison.AreEqual(strA[1], strB[1])) { // ... }
if(Comparison.AreEqual(strA[2], strB[2])) { // ... }
if(Comparison.AreEqual(strA[3], strB[3])) { // ... }
如果您以后發現需要擔心其他情況,例如忽略字符串開頭或結尾的空格,這種方法也更容易擴展; 然后,您可以向您的函數添加更多邏輯以進行一些修剪或其他操作,您無需對調用您的函數的數百行代碼進行任何修改。
不像 ?? 那樣性感,但如果你將它短路,你可以避免部分時間的雙重比較:
string.IsNullOrEmpty( strA ) ? string.IsNullOrEmpty( strB ) : (strA == strB )
關於什么
strA ?? "" == strB ?? ""
添加幾年后,寫了幾個相等比較器,我的觀點發生了變化,因此我認為相等比較器最好有一個靜態成員來保存創建的比較器,而不是每個用戶都創建一個新實例。
(原始答案,經過上述調整)
其他人給出的解決方案,包括建議為字符串定義一個比較類的解決方案,忘記為您的字符串編寫一個新的GetHashCode
。
這意味着您的字符串不能用於依賴GetHashCode
類,如Dictionary<T>
或HashSet<T>
。
請參閱為什么在覆蓋 Equals 方法時覆蓋 GetHashCode 很重要?
每當您決定更改任何類的平等概念時,您都應該為該類編寫一個EqualityComparer
。 這確保如果根據您更改的對象相等定義被視為相等,則它們的GetHashCode
將返回相等的值。
public class NullStringComparer : EqualityComparer<string>
{
public static IEqualityComparer<string> NullEqualsEmptyComparer {get} = new NullStringComparer();
public override bool Equals(string x, string y)
{
// equal if string.Equals(x, y)
// or both StringIsNullOrEmpty
return String.Equals(x, y)
|| (String.IsNullOrEmpty(x) && String.IsNullOrEmpty(y));
}
public override int GetHashCode(string obj)
{
if (String.IsNullOrEmpty(obj))
return 0;
else
return obj.GetHashCode();
}
}
用法:
public static void Main()
{
string x = null;
string y = String.Empty;
Console.WriteLine("Standard string comparison: {0}",
StringComparer.Ordinal.Equals(x, y));
Console.WriteLine($"My string comparison {0}",
NullStringComparer.NullEqualsEmpty.Equals(x, y));
// because according to the NullStringComparer x equals y
// GetHashCode should return the same value
int hashX = NullStringComparer.NullEqualsEmpty.GetHashCode(x);
int hashY = NullStringComparer.NullEqualsEmpty.GetHashCode(y);
Console.WriteLine($"hash X = {hashX}, hash Y = {hashY}");
}
string.IsNullOrEmpty() 有什么問題? 我敢肯定,由於它是 .NET 框架的一部分,因此它經過優化,並且可能比您或我可以編寫的東西高效得多。 它可能不性感,但它有效。 編寫易於閱讀的代碼,讓編譯器整理出細節。
如果您的 2 組字段位於某種集合中,則可以使用 LINQ 來發揮自己的優勢。 如果它們位於某種允許您通過鍵訪問它們的集合中,並且它們都具有相同的鍵,則您可以使用它(准備粘貼到LINQPad 中):
Dictionary<string,string> fields1 = new Dictionary<string,string>();
Dictionary<string,string> fields2 = new Dictionary<string,string>();
fields1.Add("field1", "this");
fields2.Add("field1", "this");
fields1.Add("field2", "is");
fields2.Add("field2", "");
fields1.Add("field3", "a");
fields2.Add("field3", null);
fields1.Add("field4", "test");
fields2.Add("field4", "test");
var test =
from f1 in fields1
join f2 in fields2
on f1.Key equals f2.Key
select (f1.Value ?? "") == (f2.Value ?? "");
test.Dump();
如果您在 2 個索引集合中以相同的順序擁有一組字段,則可以使用以下內容:
string[] strings1 = { "this", "is", "a", "test" };
string[] strings2 = { "this", "", null, "test" };
var test =
from s1 in strings1.Select((value,index) => new {value, index})
join s2 in strings2.Select((value,index) => new {value, index})
on s1.index equals s2.index
select (s1.value ?? "") == (s2.value ?? "");
test.Dump();
這也有效,忽略大小寫
(strA ?? "").Equals(strB ?? "", StringComparison.OrdinalIgnoreCase)
public ActionResult<ICollection<Product>> Get()
{
public string x = null;
if(string.IsNullOrEmpty(x))
return StatusCode(404, "product null");
else
return new Product();
}
此代碼在 GET 請求中返回帶有自定義代碼和消息的錯誤。
這樣,您就可以創建一個全局錯誤處理程序。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.