簡體   English   中英

字符串比較,其中 null 和 empty 相等

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM