c# - 在 C# 中创建不可变类的最简洁方法是什么?

标签 c# tuples immutability

我发现自己必须创建大量不可变类,并且我想找到一种方法来完成它而没有冗余信息。我不能使用匿名类型,因为我需要从方法中返回这些类。我想要智能感知支持,所以我不想使用字典、动态或类似的东西。我还想要命名良好的属性,这排除了 Tuple<>。到目前为止,我已经尝试过一些模式:

// inherit Tuple<>. This has the added benefit of giving you Equals() and GetHashCode()
public class MyImmutable : Tuple<int, string, bool> {
   public MyImmutable(int field1, string field2, bool field3) : base(field1, field2, field3) { }

   public int Field1 { get { return this.Item1; } }
   public string Field2 { get { return this.Item2; } }
   public bool Field3 { get { return this.Item3; } }
}

///////////////////////////////////////////////////////////////////////////////////

// using a custom SetOnce<T> struct that throws an error if set twice or if read before being set
// the nice thing about this approach is that you can skip writing a constructor and 
// use object initializer syntax.
public class MyImmutable {
    private SetOnce<int> _field1;
    private SetOnce<string> _field2;
    private SetOnce<bool> _field3;


   public int Field1 { get { return this._field1.Value; } set { this._field1.Value = value; }
   public string Field2 { get { return this._field2.Value; } set { this._field2.Value = value; }
   public bool Field3 { get { return this._field3.Value; } set { this._field3.Value = value; }
}

///////////////////////////////////////////////////////////////////////////////////

// EDIT: another idea I thought of: create an Immutable<T> type which allows you to
// easily expose types with simple get/set properties as immutable
public class Immutable<T> {
    private readonly Dictionary<PropertyInfo, object> _values;       

    public Immutable(T obj) {
        // if we are worried about the performance of this reflection, we could always statically cache
        // the getters as compiled delegates
        this._values = typeof(T).GetProperties()
            .Where(pi => pi.CanRead)
            // Utils.MemberComparer is a static IEqualityComparer that correctly compares
            // members so that ReflectedType is ignored
            .ToDictionary(pi => pi, pi => pi.GetValue(obj, null), Utils.MemberComparer);
    }

    public TProperty Get<TProperty>(Expression<Func<T, TProperty>> propertyAccessor) {
        var prop = (PropertyInfo)((MemberExpression)propertyAccessor.Body).Member;
        return (TProperty)this._values[prop];
    }
}

// usage
public class Mutable { int A { get; set; } }

// we could easily write a ToImmutable extension that would give us type inference
var immutable = new Immutable<Mutable>(new Mutable { A = 5 });
var a = immutable.Get(m => m.A);

// obviously, this is less performant than the other suggestions and somewhat clumsier to use.
// However, it does make declaring the immutable type quite concise, and has the advantage that we can make
// any mutable type immutable

///////////////////////////////////////////////////////////////////////////////////

// EDIT: Phil Patterson and others mentioned the following pattern
// this seems to be roughly the same # characters as with Tuple<>, but results in many
// more lines and doesn't give you free Equals() and GetHashCode()
public class MyImmutable 
{
   public MyImmutable(int field1, string field2, bool field3)
   {
        Field1 = field1;
        Field2 = field2;
        Field3 = field3;
   }

   public int Field1 { get; private set; }
   public string Field2 { get; private set; }
   public bool Field3 { get; private set; }
}

这些都比创建只读字段、通过构造函数设置它们并通过属性公开它们的“标准”模式更简洁。然而,这两种方法仍然存在大量冗余样板。

有什么想法吗?

最佳答案

您可以将自动属性与私有(private) setter 一起使用

public class MyImmutable 
{
   public MyImmutable(int field1, string field2, bool field3)
   {
        Field1 = field1;
        Field2 = field2;
        Field3 = field3;
   }

   public int Field1 { get; private set; }
   public string Field2 { get; private set; }
   public bool Field3 { get; private set; }
}

关于c# - 在 C# 中创建不可变类的最简洁方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15283109/

相关文章:

javascript - 根据条件设置多个 const 值

c# - 尝试更改图像时内存不足崩溃?

c# - 如何检查某些内容是否等于 C# 中的任何值列表

c# - 无法解析目标框架 '.NETFramework,Version=v4.6.1' 的 mscorlib

具有接口(interface)类型约束的 C# 泛型方法

python - 列表到元组组

python - "change"元组元素的优雅方法是什么?

Java,使类不可变

immutability - 如何创建对不可变类的可重新分配引用?

python - Python 中的两个变量具有相同的 id,但不是列表或元组