2013-05-14 72 views
1

我在今天遇到了一些非常奇怪的行为,同时重构了一些代码。如何检查泛型对象是否适用于字符串

我有一些代码,看起来是这样的:

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(); 
     } 
    } 

我anonomised类型和变量名,因为它们不是这个问题很重要。

_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); 
    } 

变戏法似的 - 一切工作和测试再次通过

回答

4

你可以使用Object.Equals

return NullOrCheck(value, v => object.Equals(v, expected)); 

stringoverloads静态==运算符来比较它的两个字符串参数是否相等,即

string first = "abc"; 
string second = "abc"; 

bool eq = first == second; 

==的通话将使用字符串重载==,因为静态类型的firstsecond都是string

然而,在

object first = "abc"; 
object second = "abc"; 
bool eq = first == second; 

==操作者使用将是自静态类型的firstsecond是对象由object定义的一个。请注意,在这种情况下,由于字符串interning,firstsecond实际上将包含对相同字符串的引用,但通常情况并非如此。

在一般方法中,==将解析为为object定义的静态==,而不是为string定义的更具体的版本。由于==是对object s的简单参考相等性检查,因此其行为有所不同。

Equals方法是虚拟的,可以重写以专门为自定义类型进行相等性检查。因此,在

object first = "abc"; 
object second = "abc"; 
bool eq = first.Equals(second); 

string.Equals方法将被调用,这会检查,而不是仅仅在相同的附图中的字符串具有相同的值,。

静态object.Equals方法使用虚拟Equals实例方法,因此它也将检查字符串具有相同的值,而不是只指向相同的字符串实例。静态object.Equals也检查其参数为null,因此比直接调用objA.Equals(objB)更安全。

+0

它似乎也有工作要做:v.Equals(预期)。看起来像一个非常奇怪的修复,因为你会认为如果使用较少的派生==,那么相同的情况对于等于也是如此。或者我在这里错过了什么? – 2013-05-14 12:30:26

+1

@JonnyLeeds - '=='是一个静态运算符,因此根据其参数的静态类型进行解析。 “Equals”是一个虚拟方法,在运行时解析。静态Object.Equals方法也检查它的参数为null,所以'Equals(null,someObject)'返回false,而null.Equals(someObject)'在运行时抛出一个异常。 – Lee 2013-05-14 12:34:02

+0

你可以扩展一下 - 我听说过以前的静态类型的短语,但没有正确解释它。顺便说一句,知道内置于Equals中的空检查 - 大概这意味着你可以进一步简化这个方法 – 2013-05-14 12:38:15

相关问题