这个重载的含义是什么?

18

有人可以解释一下这个重载是什么意思吗?

public static bool operator ==(Shop lhs, Shop rhs)
{
    if (Object.ReferenceEquals(lhs, null))
    {
        if (Object.ReferenceEquals(rhs, null))
        {
            return true;
        }
        return false;
    }

    return lhs.Equals(rhs);
}

我从未在重载中看到过Object.ReferenceEquals方法。


5
Object.ReferenceEquals检查引用是否相等... ;) 换句话说,它检查对象是否具有相同的对象,即在物理内存地址方面。 - Rob
4
由于 Shop 类的 == 运算符被重载,代码避免使用它来测试参数是否为 null 引用。如果使用 if(lhs == null),会导致无限递归,应用程序将崩溃并抛出堆栈溢出异常。 - Oguz Ozgul
可能是重载==运算符。如何与null比较?的重复问题。 - choz
这不是重载。如果您使用不同的参数类型定义了另一个ReferenceEquals,那么这将是重载(在这种情况下是个坏主意,但对于其他方法很有用)。 - Jon Hanna
3个回答

36

此重载函数旨在比较两个 Shop 实例。它使用 Object.ReferenceEquals 判断其中一个实例是否为 null
不能使用 lhs == nullrhs == null,因为这会再次调用 operator == 并创建无限递归导致 StackOverflowException

如果两个实例都是 null,则返回 true(因为它们相等)。
如果只有一个实例是 null,则返回 false(因为它们不相等)。
如果两个实例都不是 null,则返回 ShopEquals 实现的结果。


4
你也可以使用(object)lhs == null(object)rhs == null来达到相同的效果。 - slawekwin

0

这是一个运算符重载(==的重载,而不是ReferenceEquals方法的重载)来检查两个Shop类型实例是否具有相等的引用(也就是它们是否引用相同的内存地址)。

bool result = shop1 == shop2; //shop1 and shop2 are of type Shop 

在声明 == 运算符时,您还需要重载其匹配(或对立)运算符 !=

public static bool operator ==(Shop lhs, Shop rhs) {
    if (Object.ReferenceEquals(lhs, null)) { //Check if the left-hand-side Shop is null
        if (Object.ReferenceEquals(rhs, null)) {
            return true; //both are null, equal reference
        }
        return false; //lhs is null, but rhs is not (not equal reference)
    }
    return lhs.Equals(rhs); //lhs is not null, thus can call .Equals, check if it is Equals to rhs
}

public static bool operator !=(Shop lhs, Shop rhs) { //the opposite operator
    if (Object.ReferenceEquals(lhs, null)) {
        if (Object.ReferenceEquals(rhs, null)) {
            return false;
        }
        return true;
    }
    return !lhs.Equals(rhs);
}

值得注意的是,代码中使用Object.ReferenceEquals(lhs, null)而不是lhs == null,因为后者会导致另一个重载的==被调用,直到无限递归,从而导致StackOverflowException
它们的使用方式如下:
Shop shop1 = new Shop();
Shop shop2 = new Shop();
bool result = shop1 == shop2; //this will return false, since lhs and rhs referring to two different memory address
shop2 = shop1;
result = shop1 == shop2; //this will return true, referring to the same memory location
shop1 = null;
shop2 = null;
result = shop1 == shop2; //this will return true, both are null

理解这一点,你甚至可以创建这样的东西:

public struct MyCrazyInt{ //this will reverse the result of + and -
    private int Value { get; set; }
    public MyCrazyInt(int value) :this() {
        Value = value;
    }

    public bool Equals(MyCrazyInt otherCrazy) {
        return this.Value != otherCrazy.Value; //reverse this result
    }

    public static MyCrazyInt operator +(MyCrazyInt lhs, MyCrazyInt rhs) {
        int lhsVal = lhs.Value;
        int rhsVal = rhs.Value;
        return new MyCrazyInt(lhsVal - rhsVal); //note that direct lhs-rhs will cause StackOverflow
    }

    public static MyCrazyInt operator -(MyCrazyInt lhs, MyCrazyInt rhs) {
        int lhsVal = lhs.Value;
        int rhsVal = rhs.Value;
        return new MyCrazyInt(lhsVal + rhsVal); //note that direct lhs+rhs will cause StackOverflow
    }

    public override string ToString() {
        return Value.ToString();
    }
}

然后像这样使用它

MyCrazyInt crazyInt1 = new MyCrazyInt(5);
MyCrazyInt crazyInt2 = new MyCrazyInt(3);
MyCrazyInt crazyInt3 = crazyInt1 - crazyInt2; //this will return 8
crazyInt3 = crazyInt1 + crazyInt2; //this will return 2

-8

这很容易。 "NULL"实际上是一个驻留在内存中的对象,具有引用并且可以设置为任何Base "Object"类的子类对象。

因此,以上代码首先通过将它们的引用值与“null”对象引用进行比较来检查两个“Shop”对象是否完全为空,如果它们都等于null,则它们相等并返回True。

如果只有第一个对象为空而第二个对象不为空,则返回false。

最后,如果第一个Shop对象不为空,则代码假定第二个对象不为空,并将它们的实例与Shop对象进行比较以检查它们是否相等。

我们必须使用这种方式来比较空对象的主要原因是,如果您比较空或未实例化的对象,则会获得运行时错误,因此我们需要以这种方式覆盖默认的“==”运算符。


14
你的外壳很烦人,而且我不确定“'NULL'实际上是驻留在内存中的对象”是否是正确的想法。 - user585968
如果Shop是一个结构体(ValueType),我们可以将它们定义为可空类型(Nullable<T>)。因此,在这种情况下,它们可以是可空的。 - Waxoft
最后(如果Object.ReferenceEquals(lhs, null)检查,lhs是否引用任何对象,如果它不引用任何对象,则为真。 - Waxoft

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接