多态,c#中的继承 - 基类调用重写方法?

时间:2010-05-17 11:26:35

标签: c# inheritance polymorphism derived-class base-class

此代码不起作用,但希望你能得到我在这里想要实现的目标。我有一个Money课程,我从http://www.noticeablydifferent.com/CodeSamples/Money.aspx获取,并将其扩展一点以包括货币转换。

每个项目中实际转换率的实现可能会有所不同,因此我决定将用于检索转换率的实际方法(GetCurrencyConversionRate)移动到派生类中,但ConvertTo方法包含适用于任何实现的代码假设派生类已经覆盖了GetCurrencyConversionRate,那么将它保留在父类中是有意义的吗?所以我要做的是获取一个SubMoney实例,并能够调用.ConvertTo()方法,该方法将使用覆盖的GetCurrencyConversionRate,并返回一个新的SubMoney实例。

问题是,我还没有真正理解多态性和继承的一些概念,所以不太确定我想做的事情甚至可能以我认为的方式实现,因为目前正在发生的是我最终得到一个异常,它使用了基本的GetCurrencyConversionRate方法而不是派生的方法。有些东西告诉我,我需要将ConvertTo方法向下移动到派生类,但这似乎我将在多个实现中复制代码,所以肯定有更好的方法吗?

public class Money
{
    public CurrencyConversionRate
    {
        get
        {
            return GetCurrencyConversionRate(_regionInfo.ISOCurrencySymbol);
        }
    }

    public static decimal GetCurrencyConversionRate(string isoCurrencySymbol)
    {
        throw new Exception("Must override this method if you wish to use it.");
    }

    public Money ConvertTo(string cultureName)
    {          
        // convert to base USD first by dividing current amount by it's exchange rate.
        Money someMoney = this;
        decimal conversionRate = this.CurrencyConversionRate;
        decimal convertedUSDAmount = Money.Divide(someMoney, conversionRate).Amount;

        // now convert to new currency
        CultureInfo cultureInfo = new CultureInfo(cultureName);
        RegionInfo regionInfo = new RegionInfo(cultureInfo.LCID);
        conversionRate = GetCurrencyConversionRate(regionInfo.ISOCurrencySymbol);
        decimal convertedAmount = convertedUSDAmount * conversionRate;
        Money convertedMoney = new Money(convertedAmount, cultureName);
        return convertedMoney;
    }
}

public class SubMoney
{
    public SubMoney(decimal amount, string cultureName) : base(amount, cultureName) {}

    public static new decimal GetCurrencyConversionRate(string isoCurrencySymbol)
    {
        // This would get the conversion rate from some web or database source
        decimal result = new Decimal(2);
        return result;
    }
}

4 个答案:

答案 0 :(得分:3)

静态方法只能通过指定声明它的确切类来使用。没有办法让继承参与其中。

使Money类抽象化,以便必须派生它才能使用。使GetCurrencyConversionRate方法抽象(也自动使其成为虚拟)。让SubMoney类继承Money并覆盖GetCurrencyConversionRate方法:

public abstract class Money {

  public abstract decimal GetCurrencyConversionRate(string isoCurrencySymbol);

  ...

}

public class SubMoney : Money {

  public override decimal GetCurrencyConversionRate(string isoCurrencySymbol) {
    ...
  }

}

当方法在Money类中声明时,它知道它并且可以使用它。您创建实例的实际类是派生类,如SubMoney,因此始终存在该方法的实现。

答案 1 :(得分:2)

另一种选择是使用Strategy Pattern,从而抽象出转换算法,该算法作为自己的类实现。然后,您可以在运行时切换转换器的实现。这允许您通过使用某种形式的"composition over inheritance"在运行时交换算法来利用dependency injection

在设计复杂的系统之后,我确实学到了构图优于继承的好处。坦率地说,当你的目标是通过多态增加代码重用时,继承才真正有用。一旦进入复杂类型层次结构,其中继承链超过四层或五层,您最终会遇到横切关注问题(这会导致大量非常相似的代码的复制,这些代码无法在兄弟类型之间共享)。组合允许更简单的设计,易于配置(考虑使用xaml在WPF中设计复杂的表单),测试等等。

无论如何,只是为了给你一些东西来刮你的头。

答案 2 :(得分:1)

您根本没有使用继承/覆盖,而是隐藏了该方法。

public abstract class Money
{
    public CurrencyConversionRate
    {
        get
        {
            return GetCurrencyConversionRate(_regionInfo.ISOCurrencySymbol);
        }
    }

    public abstract decimal GetCurrencyConversionRate(string isoCurrencySymbol);

    public Money ConvertTo(string cultureName)
    {          
        // convert to base USD first by dividing current amount by it's exchange rate.
        Money someMoney = this;
        decimal conversionRate = this.CurrencyConversionRate;
        decimal convertedUSDAmount = Money.Divide(someMoney, conversionRate).Amount;

        // now convert to new currency
        CultureInfo cultureInfo = new CultureInfo(cultureName);
        RegionInfo regionInfo = new RegionInfo(cultureInfo.LCID);
        conversionRate = GetCurrencyConversionRate(regionInfo.ISOCurrencySymbol);
        decimal convertedAmount = convertedUSDAmount * conversionRate;
        Money convertedMoney = new Money(convertedAmount, cultureName);
        return convertedMoney;
    }
}

public class SubMoney : Money
{
    public SubMoney(decimal amount, string cultureName) : base(amount, cultureName) {}

    public override decimal GetCurrencyConversionRate(string isoCurrencySymbol)
    {
        // This would get the conversion rate from some web or database source
        decimal result = new Decimal(2);
        return result;
    }
}

如果将方法声明为抽象方法,则继承类必须覆盖此方法,通过此方法可以强制执行自定义代码。当然,你的SubMoney类必须继承Money才能做到这一点。

答案 3 :(得分:0)

GetCurrencyConversionRate是静态的。无法覆盖。