Choosing between immutable objects and structs for value objects

后端 未结 11 1596
鱼传尺愫
鱼传尺愫 2020-12-13 15:07

How do you choose between implementing a value object (the canonical example being an address) as an immutable object or a struct?

Are there performance, semantic or

11条回答
  •  没有蜡笔的小新
    2020-12-13 15:39

    I like to use a thought experiment:

    Does this object make sense when only an empty constructor is called?

    Edit at Richard E's request

    A good use of struct is to wrap primitives and scope them to valid ranges.

    For example, probability has a valid range of 0-1. Using a decimal to represent this everywhere is prone to error and requires validation at every point of usage.

    Instead, you can wrap a primitive with validation and other useful operations. This passes the thought experiment because most primitives have a natural 0 state.

    Here is an example usage of struct to represent probability:

    public struct Probability : IEquatable, IComparable
    {
        public static bool operator ==(Probability x, Probability y)
        {
            return x.Equals(y);
        }
    
        public static bool operator !=(Probability x, Probability y)
        {
            return !(x == y);
        }
    
        public static bool operator >(Probability x, Probability y)
        {
            return x.CompareTo(y) > 0;
        }
    
        public static bool operator <(Probability x, Probability y)
        {
            return x.CompareTo(y) < 0;
        }
    
        public static Probability operator +(Probability x, Probability y)
        {
            return new Probability(x._value + y._value);
        }
    
        public static Probability operator -(Probability x, Probability y)
        {
            return new Probability(x._value - y._value);
        }
    
        private decimal _value;
    
        public Probability(decimal value) : this()
        {
            if(value < 0 || value > 1)
            {
                throw new ArgumentOutOfRangeException("value");
            }
    
            _value = value;
        }
    
        public override bool Equals(object obj)
        {
            return obj is Probability && Equals((Probability) obj);
        }
    
        public override int GetHashCode()
        {
            return _value.GetHashCode();
        }
    
        public override string ToString()
        {
            return (_value * 100).ToString() + "%";
        }
    
        public bool Equals(Probability other)
        {
            return other._value.Equals(_value);
        }
    
        public int CompareTo(Probability other)
        {
            return _value.CompareTo(other._value);
        }
    
        public decimal ToDouble()
        {
            return _value;
        }
    
        public decimal WeightOutcome(double outcome)
        {
            return _value * outcome;
        }
    }
    

提交回复
热议问题