如何使用属性在c#中使用值类型?

Oop*_*ser 7 c# properties value-type

我有一个名为小班Tank有一个叫做公共成员Location这是一个Rectangle(一个结构).我写的时候:

Tank t = new Tank();
t.Location.X+=10;
Run Code Online (Sandbox Code Playgroud)

一切正常,坦克移动.

但在我将成员更改为属性后,我再也无法使用此语法.它不编译,因为t.Location它现在是一个属性(它是函数)并返回该位置的临时副本(因为它是一个值类型).

Location现在可以使用的唯一方法是做这样的事情:

k = t.Location 
k.X +=10;
t.Location = k;
Run Code Online (Sandbox Code Playgroud)

是否有任何解决方法可以帮助我不要编写这些丑陋的代码,并使用直观的a+=10;语法?

Imm*_*lue 3

来自@Servy
“结构是不可变的”,好吧,不,它们不是。在大多数情况下,它们应该是不变的,但它们并不是本质上一成不变的。这里的固有问题是该属性返回结构的副本,而不是对该结构的引用。如果 C# 中有用于 ref 返回的语法,那么这是可能的。

从根本上来说,这行不通的原因是结构是不可变的。一旦它们制作完成,就这样了。因此,不可能部分地重新分配结构。这就像试图换掉你的腿一样。你不能。它是你的一部分,你也随之而来!

我认为你唯一能做的就是实现你自己的 X 和 Y 属性,这样:

public double LocationX
{
   get
   {
       return Location.X;
   }
   set
   {
       Location = new Rectangle(value,Location.Y);
   }
}
Run Code Online (Sandbox Code Playgroud)

显然,您也需要将其镜像到 Y,但这应该允许您想要的(但不要指望它会快速或高效!)

虽然这回答了您迫在眉睫的问题,但我想就您的模型提出几点观点。我会考虑不要尝试像这样更新运动。从面向对象的角度来看,你的坦克是它自己的对象,并且应该管理它自己的位置。给它一个移动指令,然后让它更新自己的位置。

例如:

Tank.MoveRelative(10,0);   
Tank.MoveAbsolute(100,100);
Run Code Online (Sandbox Code Playgroud)

这给了你更多的自由,并允许坦克根据你给它的逻辑验证对其提出的任何请求。

  • “结构是不可变的”好吧,不,它们不是。在大多数情况下,它们“应该是”,但它们本质上并不是一成不变的。这里的固有问题是该属性返回结构的副本,而不是对该结构的引用。如果 C# 中有用于 ref 返回的语法,那么这是可能的。[以下是 Eric Lipperts 对此事的评论](http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/) (2认同)