C# 如何修改属性中的字段

C# 如何修改属性中的字段,c#,properties,struct,field,C#,Properties,Struct,Field,如何修改结构属性中的字段 例如: using System; using System.Collections.Generic; namespace ConsoleApplication1 { struct vector { public vector(int theX, int theY) { x = theX; y = theY; } public int x;

如何修改结构属性中的字段

例如:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    struct vector
    {
        public vector(int theX, int theY)
        {
            x = theX;
            y = theY;
        }
        public int x;
        public int y;
    }

    class SomeClass
    {
        public vector myVector { get; set; }
        public SomeClass()
        {
            myVector = new vector(10, 20);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            SomeClass me = new SomeClass();
            me.myVector.x = 200; //Error

            Console.Read();
        }
    }
}
如果向量是一个类,那么我可以修改它

所以我的问题是:如果它是一个结构,我如何修改它

到目前为止,我的解决方案是将当前向量设置为新向量

例如(如果我只想修改x值):


结构应该是不可变的。您不应该能够修改结构中的属性。修改
myVector
的正确方法是为属性指定一个新实例

如果您想创建更方便的API,我建议您将结构设计为:

public struct vector
{
    private readonly int x;
    private readonly int y;

    public vector(int theX, int theY)
    {
        x = theX;
        y = theY;
    }

    public int X { get { return this.x; } }
    public int Y { get { return this.y; } }

    public vector SetX(int x) 
    {
        return new vector(x, this.y);
    }

    public vector SetY(int y) 
    {
        return new vector(this.x, y);
    }
    .. other operations
}


me.myVector = me.myVector.SetX(200);

虽然前面所说的是正确的——您应该使您的结构不可变——但默认情况下它们不是这样的。您可以在现有的设置中更改结构

我最初说你需要初始化你的结构,然后注意到它是。所以我回去重新评估了这个问题,意识到我的想法不对

问题是值类型的语义。当你这样做的时候

me.myVector
您得到的是结构值的副本,而不是对它的引用。随后试图在同一行中修改该结构上的值是没有意义的

下面的代码可能会更清楚一些:

static void Main(string[] args)
{
    SomeClass me = new SomeClass();
    //me.myVector.x = 200; //Error

    // Get a local copy of the struct, which is NOT a reference to the me.myVector variable.
    vector myVec = me.myVector;
    // Now mutate the value of the local struct
    myVec.x = 3;
    int xNew = myVec.x; // xNew = 3

    int xOld = me.myVector.x; // xOld still = 10

    Console.Read();
}
因此,接下来,您可以创建一个可变值类型,您的代码将在其中工作(请注意,
myVector
属性必须是一个可直接访问的字段,或者是一个具有支持字段的属性,您可以在
MutateStruct
调用中访问该字段):


结构通常应表示以下两种情况之一:

  • 单个统一实体,例如小数或时间点(例如
    十进制
    日期

  • 用管道胶带粘在一起的自变量的小固定集合,有时可以单独使用,有时可以作为一个组使用(例如,3d点的坐标),并且除了它们包含的值之外没有任何标识(例如,任何
    点3d
    具有值[1,4,7]等同于具有相同值的任何其他值)

微软的准则适用于第一类事物,但无论谁写的,都没有考虑到一些有用的概念比第一种更适合第二种模式。听上去,您的数据类型符合第二种模式。因此,它应该将其整个状态公开为公共字段(您可以这样做)。此外,在许多情况下,如果可行,它应该作为
ref
参数传递。如果公开的字段类作为
ref
参数传递,则接收方将能够像修改相应类型的单个变量一样轻松地修改其字段。不幸的是,没有将属性公开为
ref
参数的机制。除非您编写自己的方法,将结构作为
ref
参数传递,并使用这些参数而不是属性,否则您最好的选择可能是执行以下操作:

var temp = something.myVector;
temp.X += 200;
something.myVector = temp;
另一种选择(如果
myVector
有许多字段,这可能是有利的)是在
中有一个方法,比如:

delegate void ActByRef<T1>(ref T1 p1);
delegate void ActByRef<T1>(ref T1 p1, ref T2 p2);

void modifyMyVector(ActByRef<myVector> actor) 
{
  actor(ref _myVector); // _myVector must be manual prop with backing field
}
void modifyMyVector<TX1>(ActByRef<myVector, TX1> actor, ref TX1 px1) 
{
  actor(ref _myVector, ref px1);
}
如果调用方有一个名为
velocity
向量
,并且它想将一个垂直于该向量的向量添加到
something.myVector
中,它可以执行以下操作:

something.ModifyMyVector((ref myVector vec, ref myVector vel) => 
  { vec.X += vel.Y; vec.Y -= vel.X; }, ref velocity);

请注意,在开放字段结构中使用
ref
参数可能非常有效,因为通过
ref
传递结构所需的时间与其大小无关。不幸的是,没有一个框架集合内置了任何这样的功能,而C#也没有为这样的代码提供多少便利。然而,与使用所谓“不可变”结构或不可变类的代码相比,即使使用
temp
变量的方法也更干净、更有效。

不应修改结构并使其保持不变。看看为什么:我已经初始化了我的结构,看看构造器尽管一些不理解值类型语义的程序员可能不喜欢可变结构,但这并不意味着它们“应该”是不可变的。为什么你认为.NET的设计人员在支持分段可变值语义时遇到了这么多麻烦,如果他们从来没有被使用过的话?虽然有时只有通过覆盖整个内容(例如,
Double
Decimal
)才能改变值类型是有意义的,但有时将集体意义附加到一组单独有意义的变量上也是有意义的。此外,术语“不可变结构”他用词不当。语句
Struct1=Struct2通过使用
Struct2
中相应字段的值覆盖其字段,从而变异
Struct1
<代码>结构1
在赋值后仍将引用与以前相同的实例。装箱的值类型实例始终具有可变引用语义,即使所讨论的值类型声明为“不可变”,因为赋值、装箱和byref生成都发生在类型的控制之外。
delegate void ActByRef<T1>(ref T1 p1);
delegate void ActByRef<T1>(ref T1 p1, ref T2 p2);

void modifyMyVector(ActByRef<myVector> actor) 
{
  actor(ref _myVector); // _myVector must be manual prop with backing field
}
void modifyMyVector<TX1>(ActByRef<myVector, TX1> actor, ref TX1 px1) 
{
  actor(ref _myVector, ref px1);
}
something.ModifyMyVector((ref myVector vec) => vec.X+=4;)
something.ModifyMyVector((ref myVector vec, ref myVector vel) => 
  { vec.X += vel.Y; vec.Y -= vel.X; }, ref velocity);