C# 对属性的字段或属性进行赋值时会发生什么情况

C# 对属性的字段或属性进行赋值时会发生什么情况,c#,properties,get,set,C#,Properties,Get,Set,假设您拥有如下属性: Person person1; public Person Captin{ get{ return person1; } set{ person1 = value; } } public void SomeFunction(){ Captin.name = "Hook" } 在本例中,如果在属性上设置名称,我们知道Hook的新名称将应用于person1的基础值。如果我们的实施有点不同,那该怎么办

假设您拥有如下属性:

Person person1;


public Person Captin{
    get{
        return person1;
    }
    set{
        person1 = value;
    }
}

public void SomeFunction(){
    Captin.name = "Hook"
}
在本例中,如果在属性上设置名称,我们知道Hook的新名称将应用于person1的基础值。如果我们的实施有点不同,那该怎么办呢

public Person Captin{
    get{
        return ReadCaptinFromDisk();
    }
    set{
        WriteCaptinToDisk(value);
    }
}

public void SomeFunction(){
    Captin.name = "Hook"
}
在这种情况下,为了正确设置基础值,我们需要调用Captin的set代码,作为Captin.name赋值的一部分


我想知道参数集代码是否会在字段赋值时调用集合,或者在属性引用时调用方法。特别是在这种情况下,需要将值传播到磁盘(等)。

每次访问属性Captin时,它都会从磁盘读取。但是,如果更改属性“name”,它将不会写入磁盘。只有在执行以下操作时,它才会写入磁盘

public void SomeFunction() {
   Person p = Captin;
   p.name = "Hook";
   Captin = p;
}

每次访问属性Captin时,它都将从磁盘读取。但是,如果更改属性“name”,它将不会写入磁盘。只有在执行以下操作时,它才会写入磁盘

public void SomeFunction() {
   Person p = Captin;
   p.name = "Hook";
   Captin = p;
}

正如@Joe所指出的,它不会写入磁盘。我只是想补充一点,这是因为您只使用getter,而不是setter@乔的例子使用了这两种方法


在我看来,这不仅是对getter的一种非常糟糕的使用,而且违反了关注点的分离。您应该有一个处理持久化数据的数据层。此逻辑不应在您的业务对象中。

正如@Joe所指出的,它不会写入磁盘。我只是想补充一点,这是因为您只使用getter,而不是setter@乔的例子使用了这两种方法


在我看来,这不仅是对getter的一种非常糟糕的使用,而且违反了关注点的分离。您应该有一个处理持久化数据的数据层。此逻辑不应出现在您的业务对象中。

只有当有人实际直接分配给属性时,才会调用该属性的setter

至于您的代码是否正常:这是一个文档问题

无论何时,当你有一个属性返回一些可变的东西时,你应该指出它的突变是否会起作用。您是返回“真实”数据的副本,还是真实数据本身?当属性(或普通方法)返回某种集合时,经常会出现这种情况—它是可变的?如果我改变它会发生什么

如果您记录了您的属性,说明返回的数据只是一个副本,并且更改不会在任何地方反映出来,这很好。如果你让它模棱两可,那你就会遇到问题


不变性消除了这些顾虑,当然…

只有在有人实际直接分配属性时才会调用属性的setter

至于您的代码是否正常:这是一个文档问题

无论何时,当你有一个属性返回一些可变的东西时,你应该指出它的突变是否会起作用。您是返回“真实”数据的副本,还是真实数据本身?当属性(或普通方法)返回某种集合时,经常会出现这种情况—它是可变的?如果我改变它会发生什么

如果您记录了您的属性,说明返回的数据只是一个副本,并且更改不会在任何地方反映出来,这很好。如果你让它模棱两可,那你就会遇到问题


不变性消除了这些顾虑,当然…

类类型变量、参数、字段、返回值或其他此类存储位置应被视为包含“对象id”。如果某个对象
Foo
具有一个名为
Bar
的属性,该属性属于某个类类型,由字段
\u Bar
支持,并且
\u Bar
持有“object id#24601”,则语句
Foo.Bar.Text=“George”
将调用对象#24601上的
文本设置器,其值为“George”。请注意,此语句不会修改对象
Foo
本身(其字段
\u-Bar
将在语句执行前保留“object id#24601”,执行后仍保留该字段);然而,它很可能会影响对象24601

结构类型的存储位置应被视为包含其所有字段(公共和私有)的内容。如果
Foo.Boz
Rectangle
(结构)类型的属性和支持字段
\u-Boz
,访问
Foo.Boz
将创建一个新的
Rectangle
类型的临时实例,其所有字段都将从
Foo.\u-Boz
的字段复制。尝试读取
Foo.Boz.X
会将
\u Boz
的所有字段复制到一个临时实例,然后访问该实例的字段
X

请注意,一些非常古老和邪恶的C#编译器会解释类似
Foo.Boz.X=5的代码作为<代码>矩形温度;温度X=5,丢弃temp的结果值,但不发出任何警告。这样的编译器行为导致一些人声明结构应该是“不可变的”,以确保这样的代码将生成编译器错误,而不是产生虚假的行为。不幸的是,这种信念一直持续到今天,尽管任何一个体面的编译器都会禁止这样的代码,即使
X
是一个可变字段

请注意,更新可变结构类型属性的正确惯用方法是:

Rectangle temp = MyListOFRectangles[5]; temp.X = 5; MyListOFRectangles[5] = temp; 矩形温度=MyListOFRectangles[5]; 温度X=5; MyListOFRectangles[5]=温度; 如果已知
Rectangle
有一个名为
X
的公共整数字段,并且
MyListOfRectangles
是一个
列表
,则不需要知道
Rectangle
的任何其他属性、构造函数等。要知道上述代码将更改
MyListOfRectangles[5].X
但不影响
MyListFrectangles[5]
的任何其他属性,也不影响
MyListFrectangles[4]
的任何属性。漂亮、清晰、简单。暴露的字段结构允许piec