Say you have a Price object that accepts either an (int quantity, decimal price) or a string containing "4/$3.99". Is there a way to limit which properties can be set together? Feel free to correct me in my logic below.
The Test: A and B are equal to each other, but the C example should not be allowed. Thus the question How to enforce that all three parameters are not invoked as in the C example?
AdPrice A = new AdPrice { priceText = "4/$3.99"}; // Valid
AdPrice B = new AdPrice { qty = 4, price = 3.99m}; // Valid
AdPrice C = new AdPrice { qty = 4, priceText = "2/$1.99", price = 3.99m};// Not
The class:
public class AdPrice {
private int _qty;
private decimal _price;
private string _priceText;
The constructors:
public AdPrice () : this( qty: 0, price: 0.0m) {} // Default Constructor
public AdPrice (int qty = 0, decimal price = 0.0m) { // Numbers only
this.qty = qty;
this.price = price; }
public AdPrice (string priceText = "0/$0.00") { // String only
this.priceText = priceText; }
The Methods:
private void SetPriceValues() {
var matches = Regex.Match(_priceText,
@"^\s?((?<qty>\d+)\s?/)?\s?[$]?\s?(?<price>[0-9]?\.?[0-9]?[0-9]?)");
if( matches.Success) {
if (!Decimal.TryParse(matches.Groups["price"].Value,
out this._price))
this._price = 0.0m;
if (!Int32.TryParse(matches.Groups["qty"].Value,
out this._qty))
this._qty = (this._price > 0 ? 1 : 0);
else
if (this._price > 0 && this._qty == 0)
this._qty = 1;
} }
private void SetPriceString() {
this._priceText = (this._qty > 1 ?
this._qty.ToString() + '/' : "") +
String.Format("{0:C}",this.price);
}
The Accessors:
public int qty {
get { return this._qty; }
set { this._qty = value; this.SetPriceString(); } }
public decimal price {
get { return this._price; }
set { this._price = value; this.SetPriceString(); } }
public string priceText {
get { return this._priceText; }
set { this._priceText = value; this.SetPriceValues(); } }
}
Hmmmm.... instead of fighting the compiler, maybe you just need to rethink your API. Have you considered the following:
No setters. Your class should be immutable, so that its fully initialized through the constructor and can't ever be initialized in an invalid state.
If you insist on setters, then your PriceText property can be readonly while the others are read/write. At least in doing this, you don't need to validate text passed into that property.
Maybe remove the PriceText property entirely, override the string representation of your object in the .ToString method.
The last option is the best approach in my opinion. I don't think users should be passing in pseudo-serialized strings to your class, because it requires parsing and validating -- and the burden should really be on the client using your class than your class itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With