полиморфизм, наследование в c # - базовый класс, вызывающий переопределенный метод? - PullRequest
0 голосов
/ 17 мая 2010

Этот код не работает, но, надеюсь, вы получите то, чего я пытаюсь достичь здесь. У меня есть класс 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 ]

3 голосов
/ 17 мая 2010

Статический метод можно использовать, только указав точный класс, в котором он объявлен. В этом нет никакого способа привлечь наследство.

Сделайте класс 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, поэтому всегда существует реализация метода.

2 голосов
/ 17 мая 2010

Другой вариант - использовать шаблон стратегии , в котором вы абстрагируете алгоритм преобразования, который реализован в виде своего собственного класса. Затем вы можете отключить реализацию конвертера во время выполнения. Это позволяет вам использовать преимущества «композиция перед наследованием» путем замены алгоритмов во время выполнения с использованием некоторой формы внедрения зависимостей .

После проектирования сложной системы я определенно осознал преимущества композиции перед наследованием. Честно говоря, наследование действительно полезно только тогда, когда ваша цель - увеличить повторное использование кода с помощью полиморфизма. Как только вы попадаете в иерархии сложных типов, где цепочка наследования имеет глубину более четырех или пяти уровней, вы в конечном итоге сталкиваетесь со сквозными проблемами (что приводит к большому количеству копирования очень похожего кода, который нельзя разделить между типами-братьями). Композиция позволяет упростить дизайн, упростить настройку (например, проектирование сложной формы в WPF с использованием xaml), тестирование и т. Д. И т. Д.

Во всяком случае, просто чтобы дать вам что-то, чтобы почесать голову.

1 голос
/ 17 мая 2010

Вы вообще не используете Наследование / Переопределение, вы скрываете метод.

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 должен унаследовать деньги, чтобы сделать это.

0 голосов
/ 17 мая 2010

GetCurrencyConversionRate статично. Не может быть переопределено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...