2016-04-21 76 views
8

遍及Stack Overflow和Internet我发现保持结构不变是一个很好的设计原则。不幸的是,我从来没有看到任何实际上导致这些结构真正不可变的实现。如何使一个结构不可变?

假设一个结构里面没有任何引用类型,我怎么才能让一个结构不可变?也就是说,我如何防止其任何原始字段(可能是编译时/运行时异常)的突变?

我写了一个简单的测试试图做一个结构不变,但即使不使用System.ComponentModel.ImmutableObjectAttribute工作:

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

有点OT,但有一些具体的原因,你需要一个结构,而不是只使用一个类?我还没有找到一个使用情况,其中一个结构比多年LOB编程中的类更可取。 – StingyJack

+0

将字段标记为只读?另外,你有没有看到这个:http://stackoverflow.com/questions/29974301/should-a-c-sharp-struct-have-only-read-only-properties – Pawel

+0

该结构头脑类似于C++的位域结构。该结构被实例化,我的愿望是结构将永远不会改变 - 有一个承诺,我没有意外修改数据。 –

回答

12

使字段private readonly并通过启动人在构造

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

与C#6.0(Visual Studio的2015年)的初始值,您可以使用getter只有只读字段和getter只有属性可以被初始化或者在构造函数性质

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

注或者在课堂上,也可以使用现场或财产初始值设定程序public int Field1 { get; } = 7;

不保证构造函数在结构上运行。例如。如果你有一个结构数组,你必须为每个数组元素明确地调用初始化器。对于引用类型的数组,首先将所有元素初始化为null,这很明显,您必须在每个元素上调用new。但是对于像结构体这样的值类型,很容易忘记它。

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

Field3仍然被认为是可变的,因为它是一个引用类型。您必须在getter中返回该对象的副本以保持实例不可变。 – Crowcoder

+2

或使被引用的对象本身不可变。 'String'是一个引用类型,但不可变。由于结构代表值类型,因此引用可变引用类型也可能不是一个好主意。 –

+0

好的答案!它的工作和最新!顺便说一句,如果你有一个属性初始值设定项,它只能出现在一个类中。否则,您将收到错误:''不能在结构体中包含实例属性或字段初始值设定项“。 –

3

保持你的不可变的数据私人:

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

或者更简洁:

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; } 
} 
相关问题