假设您有一个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

班级:

public class AdPrice {
    private int _qty;
    private decimal _price;
    private string _priceText;

构造函数:

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

方法:

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

访问者:

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

#1楼 票数:11

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

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

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

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

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

#2楼 票数:5

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

#3楼 票数:5

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

例如

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

这里, FromString是一个静态方法。
如果你想看一个例子,这与Enum.Parse相同。

#4楼 票数:2 已采纳

如果你只是能够像你一样直接为属性赋值, 并且有一个默认的构造函数,为什么还要使用构造函数呢?

如果priceTextprice / qty都需要外部可变,那么在什么条件下你会认为对象初始化是完整的: -

AdPrice C = new AdPrice();
C.qty = 4;
C.priceText = "2/$1.99";
C.price = 3.99m

以上是与没有“合成糖”的情况相同的代码。 为了防止您的示例发生,您需要能够阻止上述情况。

我的建议是将priceText属性priceText私有。 要使用字符串初始化对象,需要使用适当的构造函数。

#5楼 票数:2

我建议将属性设置者设为私有,只提供两个构造函数 - 一个接受数量和价格,一个接受文本表示。 在我看来,您的价格类型具有值类型语义,因此应该是不可变的。

此外,我认为对象初始化器严重过度使用。 在调用构造函数之后,对象应该完全初始化并处于满足所有不变量的一致状态。 您可以通过提供一组设计良好的构造函数来强制执行此操作,但通常无法通过提供默认构造函数并依赖于对象初始值设定项的使用来强制执行此操作。 消费者可以自由地调用默认构造函数而不执行任何其他操作。

var employee = new Employee { Id = 42, FirstName = "John", LastName = "Doe" };

在我看来,这是非常糟糕的设计。 以下代码的语义是什么?

var employee = new Employee();

它只是一个没有任何属性的对象。 无用。 我相信通过不提供默认构造函数来强制执行员工至少具有id会更好。 如果每个雇员实例都需要其他属性的值取决于实际上下文,但如果他们具有此属性,则当然应该成为构造函数参数。

var employee = new Employee(42);

  ask by Zachary Scott translate from so

未解决问题?本站智能推荐:

2回复

需要许多参数时,C#中的对象初始化程序与构造函数

我正在开发一个框架,以从C#应用程序访问EVE Online API。 本质上,API通过客户端向EVE Online服务器发送GET请求来工作,然后服务器以XML文件的形式发送响应。 我的框架将这些XML文件中的信息解析为对象。 来自请求的信息无法修改(即,无法从客户端应用程序更改服务器
1回复

关于C#中的System.Object构造函数类

创建对象时,将在类的构造函数中调用对象类构造函数。 对象构造函数中会发生什么?
1回复

没有显式构造函数和只读属性的C#类[重复]

这个问题已经在这里有了答案: 只读集合属性的C#对象初始化 4个答案 有人可以解释一下此代码的工作原理吗? “儿童”属性为“只读”(因为它没有设置器)。 “ GetFamilyTree”函数似乎使用了一个隐式的初始化方法,该方法对于“ Name”属性非常有用,因为可以在“
5回复

C#中的构造函数与对象初始值设定项的优先级

我最近一直在学习 C# 中的对象初始值设定项,但现在我想知道当它与构造函数冲突时它是如何工作的。 当我尝试这个时会发生什么? 构造函数中的默认值是否是让bool开始为 true 并且可以更改的好方法?
2回复

lambda表达式的对象initzializer/构造函数自引用

我有一个简单的过滤器类看起来像这样: 是否可以使用本地值在构造函数或对象初始值设定项中初始化Match函数? 过滤器创建后分配的示例: 是否可以将示例缩减为一个语句?
2回复

构造函数执行前的属性初始化

我正在使用一个对象初始值设定项来创建一个具有Position属性的对象,如下所示: 据我所知,它与以下内容相同: 但我想在我的构造函数方法中使用初始化的Position属性。 有没有办法在不提供Position作为构造函数参数的情况下做到这一点?
3回复

对象初始化和“命名构造函数习语”

行。 所以我有一个值列表,我想做如下事情: 所以问题来了。 我需要上面的例子来处理命名构造函数,例如: 有什么办法可以做到吗? 基本上,我有一个静态方法需要调用来获取对象实例,我想像上面一样初始化它。 编辑:我目前没有一种简单的方法来修改 MyType 的界面,因此添加新的函数调用(虽然可能是“最佳
2回复

使用对象初始化程序语法时,“在构造函数和初始化程序中,仅支持属性或字段参数绑定”

我在实体框架查询中遇到了一个非常奇怪的问题,我花了几个小时在上面。 执行查询时,出现异常: 在构造函数和初始化程序中,LINQ to Entities仅支持属性或字段参数绑定。 说明:执行当前Web请求期间发生未处理的异常。 请查看堆栈跟踪,以获取有关错误及其在代码中起源的更多