在c#中更改结构体的属性值

本文关键字:属性 结构体 | 更新日期: 2023-09-27 18:16:47

我读了一本书,发现结构体实际上是不可变对象。但是它们有getter和setter。我想知道结构体的属性是否可以在创建后更改。

public struct Test 
{
    public string str {get; set; }
    public int int1 {get; set; }
}

'str'和'int1'的值一旦被赋值就可以改变吗?

在c#中更改结构体的属性值

结构可以是可变的也可以是不可变的,但是根据很多人的看法,它们应该是不可变的。

你的例子是一个可变结构体。

使用示例:

var t = new Test();
// t.str is null, and t.int1 is 0
t.str = "changed!"; // OK
var t2 = t;
t2.int1 = 42;
// t.int1 is still 0
var li = new List<Test> { t, t2, };
t.int1 = 666;  // OK, but copy in li is unaffected
li[0].int1 = 911;  // compile-time error, not a variable
var t3 = t2;
bool checkA = (t3 == t2);  // compile-time error, you did not overload operator ==
bool checkB = t3.Equals(t2);  // OK, true, ValueType class overrides Equals for you
bool checkC = t2.Equals(t);  // OK, false
bool checkD = object.ReferenceEquals(t, t);  // false, two distinct boxes
                                             // same as (object)t==(object)t

根据请求,这里有一种方法使struct不可变:

public struct Test 
{
    public string str { get; private set; }
    public int int1 { get; private set; }
    public Test(string str, int int1) : this()
    {
        this.str = str;
        this.int1 = int1;
    }
}
// if you introduce methods (other than constructors) that use the private setters,
// the struct will no longer be immutable

还有一个

public struct Test 
{
    readonly string m_str;
    readonly int m_int1;
    public string str { get { return m_str; } }
    public int int1 { get { return m_int1; } }
    public Test(string str, int int1)
    {
        m_str = str;
        m_int1 = int1;
    }
}

'str'和'int1'的值一旦被赋值就可以改变吗?

是的,struct的性质可以改变。struct本身不是不可变的

但是使它们不可改变被认为是一个好的设计。

From Struct Design:

X不要定义可变值类型。

可变值类型有几个问题。例如,当属性getter返回值类型时,调用者将收到一个副本。因为副本是隐式创建的,所以开发人员可能不会意识到他们正在改变副本,而不是原始值。此外,一些语言(尤其是动态语言)在使用可变值类型时也存在问题,因为即使是局部变量,在解引用时也会导致生成副本。

struct s不是自动不可变的,但是由于某些问题,强烈建议您自己使它们不可变。您可能会想到类似的问题,如果结构本身作为属性被访问,则无法更改结构的属性(这是建议将其设置为不可变的原因之一)。使用Test示例:

public struct Test {
   public string str { get; set; }
   public int int1 { get; set; }
}
// This works:
Test value = new Test();
value.str = "asdf";
value.int1 = 5;
// But this does NOT work.
Test TestProperty { get; set; }
TestProperty.str = "asdf";
TestProperty.int1 = 5;

第二部分不起作用的原因是,你只通过说TestProperty来获得一个值副本,然后你设置了副本的属性值,而不是对象中的值。

要使你的结构不可变,你可以这样做:

public struct Test {
   readonly string mStr;
   readonly int mInt1;
   public string str { get { return mStr; } }
   public int int1 { get { return mInt1; } }
   public Test(string pStr, int pInt1) {
      mStr = pStr;
      mInt1 = pInt1;
   }
}

你可以创建Test的实例,你可以读取它们的属性,但是你不能改变它们的属性,除非创建一个新的实例

可以明确地将新的实例值重新赋值给结构体。不变性意味着当你认为你在改变值时,在内存中创建一个新的实例,并且上一个副本将被垃圾收集。

注意,结构体作为一个整体是不可变的。反过来,结构字段可以是可变的,也可以是不可变的。对于您的示例,字符串字段是不可变的,而int不是。