C# 字符串比较,其中 null 和 empty 相等
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1797462/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
String Compare where null and empty are equal
提问by billb
Using C# and .NET 3.5, what's the best way to handle this situation. I have hundreds of fields to compare from various sources (mostly strings). Sometimes the source returns the string field as null and sometimes as empty. And of course, sometimes there is text in the fields. My current comparison of strA != strB isn't cutting it because strA is null and strB is "", for example. I know I could do the string.IsNullOrEmpty which results in a double comparison and some ugliness. Is there a better way to handle this? I thought extension methods, but you can't extend operators.
使用 C# 和 .NET 3.5,处理这种情况的最佳方法是什么。我有数百个字段可以从各种来源(主要是字符串)进行比较。有时源将字符串字段返回为空,有时返回为空。当然,有时字段中会有文本。例如,我目前对 strA != strB 的比较并没有削减它,因为 strA 为空而 strB 为“”。我知道我可以做 string.IsNullOrEmpty 这会导致双重比较和一些丑陋。有没有更好的方法来处理这个问题?我想到了扩展方法,但你不能扩展操作符。
I guess I'm looking for a sexy way to do this.
我想我正在寻找一种性感的方式来做到这一点。
采纳答案by Dr. Wily's Apprentice
Since you've got hundreds of comparisons to do, it sounds like you want a single function to call so that you can reduce the clutter and repetition in your code. I don't think there is a built-in function to do a null/empty string/comparison check all in one, but you could just make one yourself:
由于您要进行数百次比较,听起来您想要调用单个函数,以便减少代码中的混乱和重复。我不认为有一个内置函数可以将空/空字符串/比较检查合二为一,但您可以自己制作一个:
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);
}
}
}
Then you could just use a single call to your function for each comparison:
然后,您可以在每次比较时对您的函数进行一次调用:
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])) { // ... }
This approach is also easier to expand if you later find that you need to worry about additional situations, such as ignoring whitespace at the beginning or ending of strings; you can then just add more logic to your function to do some trimming or whatever and you won't have to make any modifications to the hundreds of lines of code calling your function.
如果您以后发现需要担心其他情况,例如忽略字符串开头或结尾的空格,这种方法也更容易扩展;然后,您可以向您的函数添加更多逻辑以进行一些修剪或其他操作,您无需对调用您的函数的数百行代码进行任何修改。
回答by iammichael
Doesn't eliminate the extra underlying comparisons, but for the sexiness factor, you could use something like this:
不会消除额外的潜在比较,但对于性感因素,您可以使用以下内容:
(strA ?? "") == (strB ?? "")
or the slightly less sexy, but preferable form:
或者稍微不那么性感但更可取的形式:
(strA ?? string.Empty) == (strB ?? string.Empty)
回答by Robin Day
What about
关于什么
strA ?? "" == strB ?? ""
回答by TLiebe
What's wrong with string.IsNullOrEmpty()? I'm sure that since it is part of the .NET framework it's optimized and probably far more efficient than something you or I could write. It may not be sexy but it works. Write code that is easily readable and let the compiler sort out the details.
string.IsNullOrEmpty() 有什么问题?我敢肯定,由于它是 .NET 框架的一部分,因此它经过优化,并且可能比您或我可以编写的东西高效得多。它可能不性感,但它有效。编写易于阅读的代码,让编译器整理出细节。
回答by Eric
Not as sexy as ??, but you could avoid the double comparison part of the time if you short-circuit it:
不像 ?? 那样性感,但如果你将它短路,你可以避免部分时间的双重比较:
string.IsNullOrEmpty( strA ) ? string.IsNullOrEmpty( strB ) : (strA == strB )
回答by Chris Breish
If you your 2 sets of fields are in some sort of collection, you may be able to use LINQ to your advantage. If they are in some sort of collection that allows you to access them by key and they both have the same keys, you can use this (ready to be pasted into LINQPad):
如果您的 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();
If you have the sets of fields in 2 indexed collections in the same order, you could use something like this:
如果您在 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();
回答by Harald Coppoolse
AdditionAfter a few years, and writing several equality comparers, my opinion has changed, such that I think it is better for the equality comparer to have a static member that holds the created comparer, instead of every user creating a new instance.
添加几年后,写了几个相等比较器,我的观点发生了变化,因此我认为相等比较器最好有一个静态成员来保存创建的比较器,而不是每个用户都创建一个新实例。
(original answer, with the adjustment mentioned above)
(原始答案,经过上述调整)
The solutions others gave, including the one that proposes to define a Comparison class for the strings, forgot to write a new GetHashCode
for your strings.
其他人给出的解决方案,包括建议为字符串定义一个比较类的解决方案,忘记GetHashCode
为您的字符串编写一个新的。
This means that your string can't be used in classes that depend upon GetHashCode
like Dictionary<T>
or HashSet<T>
.
这意味着您的字符串不能用于依赖于GetHashCode
likeDictionary<T>
或 的类中HashSet<T>
。
See Why is it important to override GetHashCode when Equals method is overridden?
请参阅 为什么在覆盖 Equals 方法时覆盖 GetHashCode 很重要?
Whenever you decide to change the concept of equalityfor any class, you should write an EqualityComparer
for that class. This makes sure that if according to your changed definition of equality to objects are considered equal, their GetHashCode
would return equal values.
每当您决定更改任何类的平等概念时,都应该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();
}
}
Usage:
用法:
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}");
}
回答by Pedro Silva
public ActionResult<ICollection<Product>> Get()
{
public string x = null;
if(string.IsNullOrEmpty(x))
return StatusCode(404, "product null");
else
return new Product();
}
This code returns an error with custom code and message in a GET request.
此代码在 GET 请求中返回带有自定义代码和消息的错误。
This way, you can create a global error handler.
这样,您就可以创建一个全局错误处理程序。