我想找一个简洁明了的方式来解决这个问题。
虽然不能消除额外的底层比较,但为了增加其吸引力,您可以使用类似以下代码:
(strA ?? "") == (strB ?? "")
或者稍微没有那么吸引人,但更可取的形式:
(strA ?? string.Empty) == (strB ?? string.Empty)
string.Empty
并不是很紧凑(不够简洁),这就是为什么我两个都包含了,但是,使用string.Empty
是首选。 - iammichael看起来你需要进行数百次比较,因此你想要一个单一的函数以便在代码中减少混乱和重复。我认为没有内置的函数可以将空值/空字符串/比较检查全部合并到一起,但你可以自己创建一个:
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 ?? ""
这也可以工作,忽略大小写
(strA ?? "").Equals(strB ?? "", StringComparison.OrdinalIgnoreCase)
补充 几年后,写了几个相等比较器之后,我的观点已经改变,我认为最好的做法是让相等比较器拥有一个静态成员来保存创建的比较器,而不是每个用户都创建一个新实例。
(原始答案,按照上述调整)
其他人提供的解决方案,包括提出为字符串定义比较类的方案,忘记了为您的字符串编写新的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框架的一部分,它被优化过,可能比你我写的代码更高效。虽然它不太性感,但它很实用。编写易于阅读的代码,让编译器处理细节。
!=
? - Chris Farmer如果您的两组字段在某种集合中,您可能可以利用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();
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();