Создание процент тип в C#
мое приложение имеет дело с процентами много. Они обычно хранятся в базе данных в письменной форме, а не в десятичной форме (50% будет храниться как 50, а не 0.5). Существует также требование, чтобы проценты форматировались последовательно по всему приложению.
С этой целью я рассматривал возможность создания структуры под названием percentage, которая инкапсулирует это поведение. Думаю, его подпись будет выглядеть примерно так это:
public struct Percentage
{
public static Percentage FromWrittenValue();
public static Percentage FromDecimalValue();
public decimal WrittenValue { get; set; }
public decimal DecimalValue { get; set; }
}
разумно ли это делать? Это, безусловно, инкапсулирует некоторую логику, которая повторяется много раз, но это простая логика, которую люди, вероятно, поймут. Я думаю, что мне нужно сделать этот тип вести себя как нормальное число, насколько это возможно, однако я опасаюсь создания неявных преобразований в десятичное число, если это еще больше запутает людей.
какие-либо предложения о том, как реализовать этот класс? или веские причины не делать этого.
7 ответов
Percentage
класс не должен заниматься форматированием самого пользовательского интерфейса. Скорее, реализовать объекта iformatprovider и использованием интерфейса icustomformatter для обработки логики форматирования.
Что касается преобразования, я бы пошел со стандартным TypeConverter маршрут, который позволит .NET правильно обрабатывать этот класс, плюс отдельный PercentageParser
служебный класс, который делегирует вызовы TypeDescriptor
для использования во внешнем коде. Кроме того, вы можете предоставить implicit
или explicit
оператор преобразования, если это необходимо.
и когда дело доходит до Percentage
, Я не вижу никаких веских причин, чтобы обернуть простой decimal
в отдельную struct
кроме семантической выразительности.
Я на самом деле немного поражен бесцеремонным отношением к качеству данных здесь. К сожалению, разговорный термин "процент" может означать одну из двух разных вещей: вероятность и дисперсию. ОП не указывает, что именно, но поскольку дисперсия обычно вычисляется, я предполагаю, что он может означать процент как вероятность или дробь (например, скидку).
на очень хорошая причина писать Percentage
класс для этой цели имеет ничего сделайте с презентацией, но убедитесь, что вы не позволяете этим глупым глупым пользователям делать такие вещи, как ввод недопустимых значений, таких как -5 и 250.
Я действительно больше думал о Probability
class: числовой тип, допустимый диапазон которого строго [0,1]. Вы можете заключить, что правило в одном месте, а не писать такой код в 37 местах:
public double VeryImportantLibraryMethodNumber37(double consumerProvidedGarbage)
{
if (consumerProvidedGarbage < 0 || consumerProvidedGarbage > 1)
throw new ArgumentOutOfRangeException("Here we go again.");
return someOtherNumber * consumerProvidedGarbage;
}
вместо этого у вас есть эта хорошая реализация. Нет, это не фантастически очевидное улучшение, но помните, вы выполнение этой проверки значения каждый раз, когда вы используете это значение.
public double VeryImportantLibraryMethodNumber37(Percentage guaranteedCleanData)
{
return someOtherNumber * guaranteedCleanData.Value;
}
я настоятельно рекомендую вам просто палка с помощью double
тип здесь (я не вижу никакой пользы для decimal
введите либо, поскольку на самом деле не требуется точность base-10 в низких десятичных знаках). Создав Percentage
введите здесь, вы действительно выполняете ненужную инкапсуляцию и просто затрудняете работу со значениями в коде. Если вы используете double
, который обычно используется для хранения процентов (среди многих других задач), вы найдете дело с BCL и другим кодом в большинстве случаев намного приятнее.
единственная дополнительная функциональность, которую я вижу, вам нужна для процентов, - это возможность легко конвертировать в / из строки процента. Это можно сделать очень просто, используя отдельные строки кода или даже методы расширения, если вы хотите немного абстрагировать его.
преобразование в процентах строку :
public static string ToPercentageString(this double value)
{
return value.ToString("#0.0%"); // e.g. 76.2%
}
конверсии процент строку :
public static double FromPercentageString(this string value)
{
return double.Parse(value.SubString(0, value.Length - 1)) / 100;
}
это кажется разумным, но я бы пересмотрел ваш интерфейс, чтобы сделать его более похожим на другие примитивные типы CLR, например, что-то вроде.
// all error checking omitted here; you would want range checks etc.
public struct Percentage
{
public Percentage(decimal value) : this()
{
this.Value = value
}
public decimal Value { get; private set; }
public static explicit operator Percentage(decimal d)
{
return new Percentage(d);
}
public static implicit operator decimal(Percentage p)
{
return this.Value;
}
public static Percentage Parse(string value)
{
return new Percentage(decimal.Parse(value));
}
public override string ToString()
{
return string.Format("{0}%", this.Value);
}
}
вы определенно также хотите реализовать IComparable<T>
и IEquatable<T>
а также все соответствующие операторы и переопределения Equals
, GetHashCode
, etc. Вы также, вероятно, также захотите рассмотреть возможность реализации IConvertible
и IFormattable
интерфейсы.
это много работы. Структура, вероятно, будет где-то в области 1000 строк и занять пару дней, чтобы сделать (я знаю это, потому что это аналогичная задача Money
struct я написал несколько месяцев назад). Если это выгодно вам с точки зрения затрат, то вперед.
Я думаю, что вы можете смешивать презентацию и логику здесь. Я бы преобразовал процент в десятичную или плавающую дробь (0.5) при получении его из базы данных, а затем позволил презентации заниматься форматированием.
Я бы не создавал отдельный класс для этого - это просто создает больше накладных расходов. Я thinkg это будет быстрее просто использовать double
переменные значение базы данных.
Если общеизвестно, что база данных хранит проценты как 50, а не 0.5, все поймут statemens как part = (percentage / 100.0) * (double)value
.
этот вопрос напоминает мне о денежном классе Шаблоны архитектуры корпоративных приложений рассказывает о - ссылка может дать вам пищу для размышлений.