【问题标题】:Reassigning member variables of a struct through properties通过属性重新分配结构的成员变量
【发布时间】:2012-07-30 05:01:53
【问题描述】:

所以我有一个按以下方式定义的结构:

    public struct Item
{
    public string _name { get; set; }
    public double _weight
    {
        get 
        {
            return _weight;
        }
        set
        {
            _weight = value;

            //Shipping cost is 100% dependent on weight. Recalculate it now.
            _shippingCost = 3.25m * (decimal)_weight;

            //Retail price is partially dependent on shipping cost and thus on weight as well.  Make sure retail price stays up to date.
            _retailPrice = 1.7m * _wholesalePrice * _shippingCost;
        }
     }
    public decimal _wholesalePrice
    {
        get
        {
            return _wholesalePrice;
        }
        set
        {
            //Retail price is partially determined by wholesale price.  Make sure  retail price stays up to date.
            _retailPrice = 1.7m * _wholesalePrice * _shippingCost;
        }
    }
    public int _quantity { get; set; }
    public decimal _shippingCost { get; private set; }
    public decimal _retailPrice { get; private set; }


    public Item(string name, double weight, decimal wholesalePrice, int quantity) : this()
    {
        _name = name;
        _weight = weight;
        _wholesalePrice = wholesalePrice;
        _quantity = quantity;
    }
//More stuff

我在另一个类中也有一个 Item 实例。当我尝试通过以下命令调用 weight 属性时,程序崩溃:

currentUIItem._weight = formattedWeight;

未提供描述性错误。请注意,此时, currentUIItem 已使用无参数默认构造函数进行了更新。现在,这是奇怪的部分。当我删除 weight 的 set 属性的自定义实现并将其替换为通用 { get;放; },作业完美无缺。

有人知道这里发生了什么吗?这是一种可以与类一起正常工作的结构吗?

【问题讨论】:

  • 结构应该是不可变的:stackoverflow.com/a/3753640/588868
  • 这一切都表明它应该是class,而不是struct。它不会影响无限递归,但是:值得注意。
  • 为什么说这一定是一堂课呢?我读到结构应该是不可变的,但由于我只使用单个线程,我不知道我会如何无意中遇到问题。
  • 我不同意它应该是一个类的想法,但我不喜欢结构的设计。只要可行,结构的设计应使其状态可以完全包含在行为合理的公共字段中,并且除了构造函数之外,不应有任何成员修改this。我将消除 _ShippingCost_RetailPrice 字段,而是将它们作为只读属性,根据 WeightWholesalePrice 计算,除非您希望允许将零售价显式设置为“覆盖”那个计算。那样的话……
  • ...我建议可能有一个具有定义语义的RetailPriceOverride 字段,或者可能使用不可变的结构或类。我通常建议不要使用可变类,因为它们的语义可能很模糊,除非它们的使用方式与可变类非常不同。

标签: c# properties struct


【解决方案1】:

您在_weight 属性的set 方法中递归调用_weight 属性。

【讨论】:

    【解决方案2】:

    看起来这会导致 StackOverflowException,因为您有无限递归。

    如果你在 setter 中设置断点:

    public double _weight
    {
        set
        {
            _weight = value;
        }
     }
    

    你会看到断点继续被命中。这是因为 setter 试图为 _weight 设置一个值。但是 _weight 不是一个变量......所以当你尝试设置它的值时,你只是回调到 setter 方法。这继续无限地发生。这同样适用于 _wholesalePrice 属性...您可能想要更多类似的东西:

    public struct Item
    {
        public string _name { get; set; }
    
        private double _weightInternal;
        public double _weight
        {
            get 
            {
                return _weightInternal;
            }
            set
            {
                _weightInternal = value;
    
                //Shipping cost is 100% dependent on weight. Recalculate it now.
                _shippingCost = 3.25m * (decimal)_weightInternal;
    
                //Retail price is partially dependent on shipping cost and thus on weight as well.  Make sure retail price stays up to date.
                _retailPrice = 1.7m * _wholesalePriceInternal * _shippingCost;
            }
        }
    
        private decimal _wholesalePriceInternal;
        public decimal _wholesalePrice
        {
            get
            {
                return _wholesalePriceInternal;
            }
            set
            {
                //Retail price is partially determined by wholesale price.  Make sure  retail price stays up to date.
                _wholesalePriceInternal = value;
                _retailPrice = 1.7m * _wholesalePriceInternal * _shippingCost;
            }
        }
        public int _quantity { get; set; }
        public decimal _shippingCost { get; private set; }
        public decimal _retailPrice { get; private set; }
    
    
        public Item(string name, double weight, decimal wholesalePrice, int quantity) : this()
        {
            _name = name;
            _weightInternal = weight;
            _wholesalePriceInternal = wholesalePrice;
            _quantity = quantity;
        }
        //More stuff
    }
    

    【讨论】:

    • 通常是 StackOverflowException,具体来说
    • 我没有意识到每次引用权重变量时都会调用该属性。很高兴知道!谢谢!
    • 没问题...很高兴它有所帮助。
    【解决方案3】:

    _weight 属性的 Setter 递归调用自身,导致 StackOverFlow 异常

    解决此问题的最简单方法是通过这种方式为属性设置一个支持字段

    private double  _weight;
    public double Weight
        {
            get 
            {
                return _weight;
            }
            set
            {
                _weight = value;
    
                //Shipping cost is 100% dependent on weight. Recalculate it now.
                _shippingCost = 3.25m * (decimal)_weight;
    
                //Retail price is partially dependent on shipping cost and thus on weight as well.  Make sure retail price stays up to date.
                _retailPrice = 1.7m * _wholesalePrice * _shippingCost;
            }
         }
    

    【讨论】:

      【解决方案4】:

      在 _weight 的设置器中,您试图设置 _weight,因此这会导致无限递归。

      尝试类似(不包括零售和运输成本的额外逻辑):

      private double _weight;
      public double Weight
      {
           get { return _weight; }
           set { _weight = value; }
      }
      

      仅使用get; set; 告诉编译器自动为您生成一个支持字段,并且与上面的代码具有相同的效果。

      还要注意使用的命名约定,字段 (_weight) 带有下划线前缀,并且应该始终是私有的。外部世界使用属性(权重)与字段交互。这种模式在整个 .NET 框架中都存在,请参阅What is the difference between a Field and a Property in C#? 了解更多信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-12-17
        • 1970-01-01
        • 2019-11-24
        • 1970-01-01
        • 2018-07-20
        • 1970-01-01
        • 2014-06-04
        • 2020-10-30
        相关资源
        最近更新 更多