How do I make a struct immutable?

早过忘川 提交于 2019-12-03 23:29:07

问题


All over Stack Overflow and the internet I see that it is a good design principle to keep structs immutable. Unfortunately, I never see any implementation that actually causes these structs to be truly immutable.

Assuming that a struct does not have any reference types inside it, how do I actually make a struct immutable? That is, how do I prevent the mutation of any of its primitive field (perhaps by a compile-time/runtime exception)?

I wrote a simple test attempting make a struct immutable, but not even using the System.ComponentModel.ImmutableObjectAttribute worked:

class Program
{
    static void Main(string[] args)
    {
        ImmutableStruct immStruct1 = new ImmutableStruct();
        Console.WriteLine(immStruct1); //Before mutation.

        immStruct1.field1 = 1;
        immStruct1.field2 = "Hello";
        immStruct1.field3 = new object();
        Console.WriteLine(immStruct1); //After 1st mutation.

        immStruct1.field1 = 2;
        immStruct1.field2 = "World";
        immStruct1.field3 = new object();
        Console.WriteLine(immStruct1); //After 2nd mutation.

        Console.ReadKey();
    }
}

[ImmutableObject(true)]
struct ImmutableStruct
{
    public int field1;
    public string field2;
    public object field3;

    public override string ToString()
    {
        string field3String = "null";
        if (field3 != null)
        {
            field3String = field3.GetHashCode().ToString();
        }
        return String.Format("Field1: {0}, Field2: {1}, Field3: {2}", field1, field2, field3String);
    }
}

回答1:


Make the fields private readonly and pass the initial values in the constructor

public struct ImmutableStruct
{
    private readonly int _field1;
    private readonly string _field2;
    private readonly object _field3;

    public ImmutableStruct(int f1, string f2, object f3)
    {
        _field1 = f1;
        _field2 = f2;
        _field3 = f3;
    }

    public int Field1 { get { return _field1; } }
    public string Field2 { get { return _field2; } }
    public object Field3 { get { return _field3; } }
}

Starting with C#6.0 (Visual Studio 2015) You can use getter only properties

public struct ImmutableStruct
{
    public ImmutableStruct(int f1, string f2, object f3)
    {
        Field1 = f1;
        Field2 = f2;
        Field3 = f3;
    }

    public int Field1 { get; }
    public string Field2 { get; }
    public object Field3 { get; }
}

Note that readonly fields and getter only properties can be initialized either in the constructor or, in classes, also with field or property initializers public int Field1 { get; } = 7;.

It is not guaranteed that the constructor is run on a struct. E.g. if you have an array of structs, you must then call the initializers explicitly for each array element. For arrays of reference types all the elements are first initialized to null, which makes it obvious that you have to call new on each element. But it is easy to forget it for value types like structs.

var immutables = new ImmutableStruct[10];
immutables[0] = new ImmutableStruct(5, "hello", new Person());

Starting with C# 7.2, you can use Read-only structs




回答2:


Keep your immutable data private:

struct ImmutableStruct
{
    private int field1;
    private string field2;
    private object field3;

    public ImmutableStruct(int f1, string f2, object f3)
    {
        field1 = f1;
        field2 = f2;
        field3 = f3;
    }

    public int Field1 => field1;
    public string Field2 => field2;
    public object Field3 => field3;
}

Or less cluttered:

struct ImmutableStruct
{
    public ImmutableStruct(int f1, string f2, object f3)
    {
        Field1 = f1;
        Field2 = f2;
        Field3 = f3;
    }

    public int Field1 { get; }
    public string Field2 { get; }
    public object Field3 { get; }
}


来源:https://stackoverflow.com/questions/36780200/how-do-i-make-a-struct-immutable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!