Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 运算符与继承_C#_Oop_Architecture_Operator Overloading - Fatal编程技术网

C# 运算符与继承

C# 运算符与继承,c#,oop,architecture,operator-overloading,C#,Oop,Architecture,Operator Overloading,我的大脑已经变成了果冻,或者我有一个心不在焉的经历,或者别的什么。我正在修补一个看起来有点像这样的类层次结构: 我的Money课程如下所示: public abstract class Money { public int Amount { get; set; } public static bool operator ==(Money leftSide, Money rightSide) { // Money can only be equal if

我的大脑已经变成了果冻,或者我有一个心不在焉的经历,或者别的什么。我正在修补一个看起来有点像这样的类层次结构:

我的
Money
课程如下所示:

public abstract class Money
{
    public int Amount { get; set; }

    public static bool operator ==(Money leftSide, Money rightSide)
    {
        // Money can only be equal if it is in the same currency.
        if (leftSide.GetType() != rightSide.GetType()) return false;
        return leftSide.Amount == rightSide.Amount;
    }

    public static bool operator !=(Money leftSide, Money rightSide)
    {
        // If the currencies are different, the amounts are always considered unequal.
        if (leftSide.GetType() != rightSide.GetType()) return true;
        return leftSide.Amount != rightSide.Amount;
    }

    public static Money operator *(Money multiplicand, int multiplier)
    {
        var result = multiplicand * multiplier;
        return result;
    }

    public static Dollar Dollar(int amount)
    {
        return new Dollar(amount);
    }

    public static Franc Franc(int amount)
    {
        return new Franc(amount);
    }
}
public static Dollar operator *(Dollar multiplicand, int multiplier)
{
    var result = multiplicand.Amount * multiplier;
    return new Dollar(result);
}
我的美元
运算符*
如下所示:

public abstract class Money
{
    public int Amount { get; set; }

    public static bool operator ==(Money leftSide, Money rightSide)
    {
        // Money can only be equal if it is in the same currency.
        if (leftSide.GetType() != rightSide.GetType()) return false;
        return leftSide.Amount == rightSide.Amount;
    }

    public static bool operator !=(Money leftSide, Money rightSide)
    {
        // If the currencies are different, the amounts are always considered unequal.
        if (leftSide.GetType() != rightSide.GetType()) return true;
        return leftSide.Amount != rightSide.Amount;
    }

    public static Money operator *(Money multiplicand, int multiplier)
    {
        var result = multiplicand * multiplier;
        return result;
    }

    public static Dollar Dollar(int amount)
    {
        return new Dollar(amount);
    }

    public static Franc Franc(int amount)
    {
        return new Franc(amount);
    }
}
public static Dollar operator *(Dollar multiplicand, int multiplier)
{
    var result = multiplicand.Amount * multiplier;
    return new Dollar(result);
}
现在,如果我运行这个测试代码,就会出现堆栈溢出(wahoo!)


我原以为这会递归地调用子类(Dollar)
操作符*
,因为(Dollar*int)是非递归定义的,所以它会返回一个确定的结果。既然这不起作用,另一种选择是我做了一些愚蠢的事情。为什么这样不行?获得这种行为的正确方法是什么?

您似乎遗漏了
。金额

public static Money operator *(Money multiplicand, int multiplier)
{
    var result = multiplicand.Amount * multiplier;
    return result;
}

问题在于,您希望可以重写派生类中的运算符,并期望。这不是C#中的工作方式。运算符重载,实际重载是在编译时选择的。这意味着以下代码是递归的,并调用自身:

public static Money operator *(Money multiplicand, int multiplier)
{
    var result = multiplicand * multiplier;
    return result;
}
您可以看到运算符重载和方法重写之间区别的另一个示例是:

int a = 5;
int b = 5;

Console.WriteLine(a == b); // true
Console.WriteLine(a.Equals(b)); // true
Console.WriteLine((object)a == (object)b); // false
Console.WriteLine(((object)a).Equals((object)b)); // true
在第三种情况下,C#将
a
b
视为对象而不是整数,因此它使用默认的
=
运算符,该运算符用于对象:比较引用(在本例中为装箱整数的引用)


这可能会使在类层次结构上定义运算符变得很尴尬,因为您希望在派生类中重新定义运算符。当行为依赖于两个操作数的组合时,这尤其令人尴尬,因为C#(以及大多数其他OOP语言)缺乏对操作数的支持。您可以使用visitor模式来解决这个问题,但我认为在这种情况下,您应该重新考虑是否为每种货币使用子类是最佳解决方案。

当出现堆栈溢出时,您应该检查堆栈。您将看到相同的函数一次又一次地相互调用。仅此一点就可以告诉您发生了什么及其原因。请注意,发生递归是因为您实际调用的是
Money.operator*
,而不是
Dollar.operator*
。运算符是重载的,而不是重写的,因此调用的函数由操作数的编译时类型而不是运行时类型决定。由于
fiveDollars
Money
类型的变量,
fiveDollars*2
调用
Money
版本的
operator*
(即使
fiveDollars
的运行时类型是
Dollar
)+1是的,这似乎确实是个问题。我确实认为运算符被重写了,我在这里学到了一些东西:)