C#:具有两个构造函数的对象:如何限制哪些属性设置在一起?

Zac*_*ott 4 c# object-initializers c#-4.0

假设您有一个Price对象接受(int数量,小数价格)或包含"4/$ 3.99"的字符串.有没有办法限制哪些属性可以设置在一起?请在下面的逻辑中随意纠正我.

测试:A和B彼此相等,但不允许使用C示例.因此,问题如何强制所有三个参数都不会像在C示例中那样被调用?

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
Run Code Online (Sandbox Code Playgroud)

班级:

public class AdPrice {
    private int _qty;
    private decimal _price;
    private string _priceText;
Run Code Online (Sandbox Code Playgroud)

构造函数:

    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; }
Run Code Online (Sandbox Code Playgroud)

方法:

    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);
    }
Run Code Online (Sandbox Code Playgroud)

访问者:

    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(); } }
}
Run Code Online (Sandbox Code Playgroud)

Jul*_*iet 11

嗯...而不是打击编译器,也许你只需要重新考虑你的API.你考虑过以下几点:

  • 没有二传手.您的类应该是不可变的,因此它通过构造函数完全初始化,并且不能在无效状态下初始化.

  • 如果您坚持使用setter,那么您的PriceText属性可以是只读的,而其他属性是可读/写的.至少在执行此操作时,您无需验证传递到该属性的文本.

  • 也许完全删除PriceText属性,覆盖.ToString方法中对象的字符串表示形式.

在我看来,最后一个选项是最好的方法.我不认为用户应该将伪序列化字符串传递给您的类,因为它需要解析和验证 - 并且负担应该真正在使用您的类而不是您自己的类本身的客户端上.


Ita*_*aro 5

如何将属性中的setter设置为private并添加方法来更改价格甚至没有方法,这样只需在实例化新对象时设置价格.


sha*_*esh 5

对于字符串部分,最好有一个静态方法来解析字符串并返回一个Price实例.

例如

Price newPrice = Price.FromString("4/$3.99");
Console.WriteLine("{0} qty for {1}", newPrice.Quantity, newPrice.Price);
Run Code Online (Sandbox Code Playgroud)

这里FromString是静态方法.
这就像Enum.Parse你想看一个例子一样.