Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 修改变量和属性之间的区别_C#_.net - Fatal编程技术网

C# 修改变量和属性之间的区别

C# 修改变量和属性之间的区别,c#,.net,C#,.net,对此可能有一个相当合理的解释,但我有一个问题 假设我有一个名为_rect的矩形类型变量。我现在可以说_rect.X=50;没有任何问题 现在我有一个类,它有一个名为Rect的属性,它公开了内部变量_Rect 然后,如果我试图写Rect.X=50我得到以下编译错误: 无法修改“TestClass.Rect”的返回值,因为它不是变量 我可以为不可变类型编写Rect=new Rectangle(50,Rect.Y,Rect.Width,Rect.Height) 我想为这个矩形字段使用自动属性,但是不能

对此可能有一个相当合理的解释,但我有一个问题

假设我有一个名为_rect的矩形类型变量。我现在可以说_rect.X=50;没有任何问题

现在我有一个类,它有一个名为Rect的属性,它公开了内部变量_Rect

然后,如果我试图写
Rect.X=50我得到以下编译错误:

无法修改“TestClass.Rect”的返回值,因为它不是变量

我可以为不可变类型编写
Rect=new Rectangle(50,Rect.Y,Rect.Width,Rect.Height)

我想为这个矩形字段使用自动属性,但是不能在类本身内部修改它真的很烦人


除了创建备份字段和删除auto属性之外,还有其他方法吗?

访问属性实际上是一个返回值类型副本的函数调用。矩形X=50;将仅修改此临时副本,而不是备份字段本身


当属性未自动实现时,您可以创建一个附加属性RectX,该属性可用于获取和设置矩形的X属性。

此错误的原因是,与引用类型(类)相比,它是一个值类型(struct)。无法修改
X
属性,因为当使用
Rect
属性getter时,将返回矩形的新值(getter是一个函数)。如果它是引用类型,那么您正在操作指针,这是可能的


这是值得注意的值与引用类型的一个重要方面。

检查此项:

您可以向我们展示您的Rect类代码吗?为什么不使用内置的Rect类呢?Rectangle是类还是结构?如果它是一个结构,试着把它变成一个类给我们一个完整的代码清单,我很难想象你在说什么,这将有助于澄清你的问题。Rect是标准的System.Drawing.Rectangle。我已经更新了我的问题以消除混淆。另请看这个问题(非重复):我现在觉得很愚蠢,因为我不理解为什么新矩形(…)有效,而不是Rect.X=50,因为两者都可以用于副本,但当我编写新矩形时,我调用的是集合而不是get。谢谢你让我清楚地知道这一点。所以这基本上意味着不。如果我想要这种类型的行为,我必须使用一个支持字段。当使用一个支持字段时,行为仍然是相同的,getter和setter仍然是方法,因此您仍然将获得矩形实例的值副本。您想要的行为仅适用于引用类型,因为这样您就可以获得对原始对象实例的“引用”。但是,矩形是一种值类型。可以肯定的是,没有任何技术原因说明编译器无法实现这一点。编译器会为用户生成各种额外的代码(例如装箱),为什么不在这里呢?(事实上,原因可能是它并不重要,因为结构无论如何都应该是不可变的。)@Konrad-structs在作为结果传递时被复制,因此该操作根本没有任何意义。这不是因为不变性(结构是可变的)。但是如果您检索一个对象的副本并更改该副本中的字段,那只是一个NOOP。@viraptor:我不同意。该操作显然是有意义的:对属性进行变异。编译器可以通过生成相当于
var tmp=foo.Property的代码轻松完成这项工作;tmp.x=newX;foo.Property=tmp
–编译器实际上在一种等效的情况下执行此操作:当您有一个值类型属性并写入
foo.property+=1
时,此操作有效(在Mono编译器上测试)。编译器清楚地将代码重写为上述内容。@Konrad:这些情况并不相同-如果
Property
的类型是一个struct,那么对于
foo.Property.x+=1
您将得到与
tmp=foo.Property等价的属性;tmp.x+=1
(其中
tmp
成为属性的副本)。如果属性本身是一个简单的值类型,那么您不需要修改关于该值本身的任何内容。生成一个新值并指定给属性本身,而不是属性的一部分。属性getter保证获得类型的副本。例如,您可以获得
1
的副本,并将
2
分配回。如果您获得了
foo.x
的副本并对其进行了修改,您可以将其分配给
x
@viraptor的副本:我同意,我自己也注意到了这一差异——请参见下面的评论,我并不是试图在这里创建新的矩形,而是为了让它与标准矩形一起工作:)
  class RectangleWithoutFields 
  {
     // just autoproperties, no fields

     public int X { get; set; }

     public int Y { get; set;}


     public RectangleWithoutFields()
     {
         X = 0;

         Y = 0; 
     }

     public void ChangeProperties(int x, int y)

     {
         X = x;

         Y = y;
     }
 }