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

我已经对类型和变量名称进行了匿名化,因为它们对问题并不重要。

_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”)是相等的。

看过以下不能将运算符 == 应用于 C# 中的泛型类型?似乎字符串是在引用相等而不是以正常方式进行比较的。

在 c# 中是否有一种安全的方法可以做到这一点,或者由于上述原因,在泛型方法中使用 == 是否应该被认为是危险的?

只是为了确认这是问题,我的修复包括在字符串大小写中内联有问题的方法,导致:

    private bool DetailsMatch(string x, AnotherType y, AFurtherType z)
    {
        return (_x == null || _x == x) &&
               NullOrCheck(_y, y) &&
               NullOrCheck(_z, z.IsSameAs);
    }

嘿 presto - 一切正常,测试再次通过

4

1 回答 1

4

您可以使用Object.Equals

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

该类string重载静态运算==符以比较其两个字符串参数是否相等,即

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

bool eq = first == second;

调用==将使用重载==的字符串,因为 和 的静态first类型second都是string

然而,在

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

使用的==运算符将是定义的运算符,因为andobject的静态类型是对象。请注意,在这种情况下,由于字符串实习,实际上将包含对同一字符串的引用,但通常情况并非如此。firstsecondfirstsecond

在泛型方法中,==将解析为为==定义的静态object而不是为 定义的更具体的版本string。由于==是对 s 的简单引用相等检查object,因此其行为不同。

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

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

string.Equals方法将被调用,它将检查字符串是否具有相同的值,而不仅仅是相同的引用。

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

于 2013-05-14T12:17:18.377 回答