Creating a percentage type in C #

My application deals with percentages. They are usually stored in the database in their written form, and not in decimal form (50% will be stored as 50, not 0.5). There is also a requirement that percentages be formatted sequentially in all applications.

To this end, I considered the possibility of creating a structure called a percentage that encapsulates this behavior. I think his signature will look something like this:

public struct Percentage { public static Percentage FromWrittenValue(); public static Percentage FromDecimalValue(); public decimal WrittenValue { get; set; } public decimal DecimalValue { get; set; } } 

Is this a reasonable thing? It will encapsulate some logic that is repeated many times, but it is a simple logic that people are likely to understand. I think I need this type to behave as normal as possible, but I fear the creation of implicit conversions to the decimal system if they confuse people further.

Any suggestions on how to implement this class? or compelling reasons not to.

+6
design c #
source share
7 answers

Percentage class should not concern itself with formatting for the user interface. Rather, apply IFormatProvider and ICustomFormatter to handle formatting logic.

As for the conversion, I would go with a standard TypeConverter route that would allow .NET to handle this class correctly, plus a separate PercentageParser utility class that delegates TypeDescriptor calls for more convenient use in external code. Alternatively, you can provide an implicit or explicit conversion operator if necessary.

And when it comes to Percentage , I don’t see any convincing reason for porting a simple decimal to a separate struct , other than semantic expressiveness.

+5
source share

In fact, I'm a little overwhelmed by the gentleman regarding data quality. Unfortunately, the colloquial term “percent” can mean one of two different things: probability and deviation. The OP does not indicate which, but since the variance is usually calculated, I assume that it can mean percent as probability or fraction (e.g., discount).

a very good reason to write the Percentage class for this purpose has nothing to do with the presentation, but so that you do not allow these silly stupid users to do something like entering invalid values ​​such as -5 and 250.

What I think most about is the Probability class: a numeric type whose valid range is strictly [0,1]. You can encapsulate this rule in ONE place, and not write such code in 37 places:

  public double VeryImportantLibraryMethodNumber37(double consumerProvidedGarbage) { if (consumerProvidedGarbage < 0 || consumerProvidedGarbage > 1) throw new ArgumentOutOfRangeException("Here we go again."); return someOtherNumber * consumerProvidedGarbage; } 

instead, you have this nice implementation. No, this is not a fantastically obvious improvement, but remember that you perform this value check every time you use this value.

  public double VeryImportantLibraryMethodNumber37(Percentage guaranteedCleanData) { return someOtherNumber * guaranteedCleanData.Value; } 
+8
source share

I highly recommend you just stick with the double type here (I don't see any use for the decimal type, since it doesn't really seem to require base-10 precision in the lower decimal places). By creating the Percentage type here, you really do unnecessary encapsulation and just complicate the work with the values ​​in the code. If you use double , which is common for plot percentages (among many other tasks), in most cases you will be dealing with BCL and other code.

The only additional functionality that I see as a percentage is the ability to easily convert to / from a percentage line. This can be done very simply using single lines of code or even extension methods if you want to distract it a bit.

Convert to Percentage:

 public static string ToPercentageString(this double value) { return value.ToString("#0.0%"); // eg 76.2% } 

Converting from Percentage:

 public static double FromPercentageString(this string value) { return double.Parse(value.SubString(0, value.Length - 1)) / 100; } 
+3
source share

This seems to be reasonable, but I would revise your interface to make it more like other primitive CLR types, for example. something like.

 // 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); } } 

You would also like to implement IComparable<T> and IEquatable<T> , as well as all relevant operators and overrides of Equals , GetHashCode , etc. In addition, you will also want to consider implementing IConvertible and IFormattable .

This is a lot of work. The structure will probably be somewhere in the 1000 row area and take a couple of days (I know this because it is a similar task for the Money structure that I wrote a few months ago). If this is beneficial to you, then go for it.

+2
source share

I think you can mix presentation and logic here. I would convert the percentage to decimal or floating fraction (0.5) when I got it from the database, and then let the presentation handle the formatting.

+1
source share

I would not create a separate class for this - it just creates additional overhead. I think it will be faster to use the double variables set for the database value.

If it is well known that the database stores percentages as 50, not 0.5, everyone will understand such members as part = (percentage / 100.0) * (double)value .

+1
source share

This question reminds me of the Money class. Enterprise application architecture patterns suggests that a link can give you food for thought.

+1
source share

All Articles