2015-05-15 2 views
1

Я составляю некоторые основные типы приложений, которые будут иметь дело с деньгами. Простой денежный класс может выглядеть следующим образом:Округление денег в финансовой заявке

public class Money 
{ 
    private decimal RawAmount { get; set; } 
    public Currency Currency { get; set; } 
    public decimal Amount 
    { 
     get 
     { 
      return Math.Round(RawAmount, 2); 
     } 
     set 
     { 
      RawAmount = value; 
     } 
    } 
} 

Первоначально я думал, что это казалось хорошей идеей, пока я не должен составлять более сложные значения на основе нескольких Money.Amounts.

Проблема заключается в том, что количество каждого экземпляра Money будет округлено и поэтому может отключить нечетное значение.

Итак, мой вопрос в том, что такое рекомендуемый способ работы с деньгами, где вы ожидаете округленного вывода?

Конкретно я интересно:

  1. Есть ли способ, чтобы избежать необходимости округлить все свои значения в интерфейсе они отображаются его, я мог сделать это лучше с помощью какого-то форматировочного класса возможна?

  2. Если я работаю со сложными вычислениями, то каков наилучший способ генерации тестовых значений. Например. Если я использую decimal для своего свойства Amount и хочу протестировать результат 10/3, как бы вы порекомендовали проверить результат, просто не перефразируя расчет?

  3. Сопротивление каждого композита Amount - это путь? и просто принять неточность? Кто-нибудь есть опыт работы приложений, связанные с финансовыми (обратите внимание, что это не является серьезным банковским приложение или что-нибудь так, возможно, фракции пенсов не могут быть слишком много проблем.)

Любого вклад высоко оценило.

+0

Помните, что десятичная сумма использует округление банкиров. – garryp

+0

Выставляем закругленное и неокрашенное значение. Когда раунд и когда не может быть деталью реализации этого класса. Его в ответственности пользователей классов. – Ralf

+3

Вы не можете обойти деньги. Деньги всегда должны куда-то идти. Предполагаю, вы видели открытые сцены Супермена II? – Bathsheba

ответ

2

Мы делаем приложение, работающее с деньгами (даже с иностранной валютой, но не с банковским приложением) прямо сейчас ... (кстати, из-за моего engrish - и извините за отсутствие «общедоступного» кода, я не уверен, могу ли я просто скопируйте & вставьте что-нибудь из моей работы)

Лучший подход - просто «спросить клиента». Не ваше дело знать, каковы внутренние правила для каждого клиента.

Я знаю, что вы не спросите об иностранной валюте, так что вы можете пропустить до 4) и 5), но и для контекста ... :)

1) Внутренне, мы используем только одну валюту.

2) Каждая работа по договору с фиксированной ставкой (может быть 1: 1, если это наша внутренняя валюта). Не обращайтесь к трейдеру, чтобы спекулировать обменным курсом, поэтому они имеют фиксированную ставку по подписанному контракту & job, for следующая работа, они могут заключать новый контракт с разной ставкой)

3) Любые деньги можно проследить до работы & договор & тариф.

4) Округление может быть установлено для всего приложения (одного, двух ...п знаков после запятой) Кто-то хочет два знак после запятой, но один клиент хочет видеть 5 знаков после запятой)

5) Мы округление ТОЛЬКО для графического интерфейса & отчетов, даже тогда, если нажать на десятичном поле, вы увидите неокругленные значения , Никто не заботится об 0,1 CZK, но может заботиться о 0,01 € (что составляет 0,2 CZK ... Странно, но люди странные :))

+0

Точно. Программисту необходимо спросить об этом бухгалтеров. –

+0

Я думаю, что это разумный ответ, я согласен с тем, что требования клиентов являются ключевыми. Я в этом случае являюсь моим собственным клиентом, поэтому вы можете утверждать, что я делаю гору из мухи, но я пытаюсь понять, что другие люди используют, когда подходят к этой проблеме. – dougajmcdonald

2

Есть ли способ избежать необходимости округлять все мои значения в UI они отображаются, возможно, я могу сделать это лучше через какой-то класс форматирования, возможно?

Да:

public string ToString(string format, IFormatProvider provider) 
{ 
    return Currency + " " + RawAmount.ToString(format, provider); 
} 
public string ToString(string format) 
{ 
    return ToString(format, NumberFormatInfo.CurrentInfo); 
} 
public string ToString(IFormatProvider provider) 
{ 
    return ToString("0.00", provider); 
} 
public override string ToString() 
{ 
    return ToString(provider); 
} 

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

Если я работаю со сложными вычислениями, то какой способ генерировать тестовые значения. Например. Если я использую десятичное значение для свойства Amount и хочу проверить результат 10/3, как бы вы порекомендовали мне проверить результат, просто не перефразируя расчет?

Перефразируя вычисления вне класса. Assert.Equal(10/3, (new Amount(10)/3).Value);

Сопротивление каждого композита Сумма - это путь? и просто принять неточность? Кто-нибудь есть опыт работы приложений, связанные с финансовыми (обратите внимание, что это не является серьезным банковским приложение или что-нибудь так, возможно, фракции пенсов не могут быть слишком много проблем.)

Это зависит от причины, он используется. Если вы подсвечиваете кучу вещей, представленных пользователю по заданной цене, тогда вам придется добавить округленные значения, потому что вы сказали, что вы начисляете им USD 12.03 и USD 3.12, и поэтому они ожидают, что в общей сложности USD 15.15, поскольку это сумма того, о чем им говорили, а не 15,16 долларов США, поскольку это сумма 12.034 и 3.1246 при округлении от 15.1586 долларов США.

Если вы подсчитали кучу мелких предметов, в том числе, возможно, обмен валюты и т. Д., Вам придется держать все эти мелкие фракции до конца.

Вы также должны будете принять решение о том, следует ли применять округление банкиров (по умолчанию и та или иная на большую часть времени) или округление школьного ребенка (тип, ожидаемый некоторыми клиентами, если детали до округления должны быть видны для них) или всегда округлять вниз (юридически настаивали на некоторых переходных периодах изменения валюты).

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

Если вы собираетесь иметь такой класс, то это имело бы больше смысла, чтобы это как операция на самих объектах:

public Money Round(int decimals, MidpointRounding mode) 
{ 
    return new Money(Currency, Amount.Round(decimals, mode)); 
} 
public Money Round(MidpointRounding mode) 
{ 
    return Round(2, mode); 
} 
public Money Round(int decimals) 
{ 
    return Round(decimals, MidpointRounding.ToEven); 
} 
public Money Round() 
{ 
    return Round(2); 
} 

Там; код пользователя может решить, когда нужно округлить, а также как округлить, но с разумными значениями по умолчанию.

Я бы также рекомендовал сделать такой класс struct и определенно сделать его неизменным.

+0

Отлично, мой единственный счетчик будет отвечать на тестовые значения. Скажем, я предоставляю калькулятор, я должен проверять функцию (ввод) == output. Вместо функции (вход) == function (input). Простой пример может показаться не очень важным, но возьмите пример, когда у меня есть метод под названием «doToughMaths (1,1200,897)», и мой метод тестирования должен утверждать, что Math.Round ((1/1200) , 2)^897 * 1 - 1200 + 897/(897 * (1200/1)) == doToughMaths (1,1200,897) .Результат, (как я понял), мне кажется, что мне нужно реплицировать сложную логику в моих тестах, которые могут быть удивительно хрупкими. – dougajmcdonald