我今天遇到了一些非常奇怪的行为,同时重构了一些代码。
我有一些看起来像这样的代码:
private AType Blah
{
get
{
return (from something in AList
where _x == null || something.x == _x
where _y == null || something.y == _y
where _z == null || something.z.IsSameAs(_z)
select something).Single();
}
}
我已经对类型和变量名称进行了分类,因为它们对问题并不重要。
_x和something.x的类型是字符串,_y和something.y是引用类型。同样,_z和something.z是一个带有值比较的引用类型。
我以为我可以这样做:
public AType Blah
{
get { return AList.Single(something => DetailsMatch(something.x, something.y, something.z)); }
}
private bool DetailsMatch(string x, AnotherType y, AFurtherType z)
{
return NullOrCheck(_x, x) &&
NullOrCheck(_y, y) &&
NullOrCheck(_z, z.IsSameAs);
}
private bool NullOrCheck<T>(T value, T expected) where T : class
{
return NullOrCheck(value, v => v == expected);
}
private static bool NullOrCheck<T>(T value, Func<T,bool> check) where T : class
{
return value == null || check(value);
}
这一切似乎都有意义,但令我惊讶的是,一些测试开始失败。事实证明,使用==运算符不再将相同的字符串(示例为“1A04”和“1A04”)视为相等。
看了下面的Can't operator == be applied to generic types in C#?之后,似乎很可能是在引用等式上而不是以正常方式比较字符串。
有没有一种安全的方法在c#中执行此操作,或者在通用方法中使用==因上述原因而被视为危险?
只是为了确认这是问题我的修复包括在字符串案例中内联违规方法导致:
private bool DetailsMatch(string x, AnotherType y, AFurtherType z)
{
return (_x == null || _x == x) &&
NullOrCheck(_y, y) &&
NullOrCheck(_z, z.IsSameAs);
}
嘿presto - 一切正常,测试再次通过
答案 0 :(得分:4)
您可以使用Object.Equals
:
return NullOrCheck(value, v => object.Equals(v, expected));
string
类overloads静态==
运算符,用于比较其两个字符串参数是否相等,即
string first = "abc";
string second = "abc";
bool eq = first == second;
对==
的调用将使用重载的==
作为字符串,因为first
和second
的静态类型都是string
。
然而,在
object first = "abc";
object second = "abc";
bool eq = first == second;
使用的==
运算符将是object
定义的运算符,因为first
和second
的静态类型是对象。请注意,在这种情况下,由于字符串实习,first
和second
实际上将包含对同一字符串的引用,但一般情况并非如此。
在通用方法中,==
将解析为==
定义的静态object
,而不是为string
定义的更具体的版本。由于==
是object
的简单引用相等检查,因此行为方式不同。
Equals
方法是虚方法,可以重写以专门对自定义类型进行相等性检查。因此在
object first = "abc";
object second = "abc";
bool eq = first.Equals(second);
将调用string.Equals
方法,它将检查字符串是否具有相同的值,而不是相同的引用。
静态object.Equals
方法使用虚拟Equals
实例方法,因此它还会检查字符串是否具有相同的值,而不是仅指向相同的字符串实例。静态object.Equals
也检查其参数为null,因此比直接调用objA.Equals(objB)
更安全。