2013-04-20 89 views
0

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

例如:

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值):

me.myVector = new vector(200,me.myVector.y); 
+0

您不应该修改一个结构并将其保留为不可变的。看到这个为什么:http://stackoverflow.com/questions/3751911/why-are-c-sharp-structs-immutable – 2013-04-20 23:14:57

回答

2

结构是应该是一成不变。你不应该能够修改你的结构中的一个属性。修改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); 
+0

好的,谢谢:) – Assassinbeast 2013-04-21 12:30:50

0

虽然什么之前已经说的是真的 - 你应该让你的结构不变 - 他们AREN那是默认的方式。你可以在你的设置中改变一个结构。

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

问题是值类型的语义。当你做

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访问支持字段)的属性:

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

    public void MutateStruct(int newX) 
    { 
     myVector.x = newX; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     SomeClass me = new SomeClass(); 

     me.MutateStruct(200); 
     int newerX = me.myVector.x; // newerX is now 200 

     Console.Read(); 
    } 
} 
+0

我已初始化我的结构,看看构造函数 – Assassinbeast 2013-04-20 23:29:53

+0

啊好吧,感谢您的帮助:) – Assassinbeast 2013-04-21 11:20:51

0

的Structs一般应代表两件事情之一:

  • 单个统一实体,例如分数或时刻(例如,一个DecimalDate)。

  • 一个固定的独立变量集合与胶带粘在一起,有时可以单独使用,有时可以作为一个组使用(例如3d点的坐标),并且超出它们包含的值因此,例如任何值为[1,4,7]的Point3d与具有相同值的任何其他值相同)。

当施加到第一类型的事情微软的指引都不错,但谁写他们没有考虑到一些有用的概念符合第二图案程度远远超过了第一。通过事物的声音,您的数据类型符合第二种模式。因此,它应该将整个国家暴露为公共领域(你这样做)。此外,在许多情况下,在实际情况下,应该以参数ref的形式通过。如果将外露字段类作为ref参数传递,则收件人将可以轻松修改其字段,因为它可以修改相应类型的单个变量。不幸的是,没有机制将属性暴露为ref参数。除非你写你自己的方法,其通过结构作为ref参数,并使用这些替代性,最好的办法可能会是做这样的事情:

var temp = something.myVector; 
temp.X += 200; 
something.myVector = temp; 

替代(这可能是有利myVector有许多字段)将有一个someThing类似的方法:

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); 
} 

一个呼叫者,想要例如添加4到myVectorX可以写

something.ModifyMyVector((ref myVector vec) => vec.X+=4;) 

如果来电者有一个vector称为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变量的方法也比使用所谓的“不可变”结构或不可变类的代码更清洁和更高效。

+0

虽然有些程序员不明白价值型语义可能不喜欢可变结构,但这并不意味着他们被认为是不可变的。为什么你认为.NET的设计者经历了太多的麻烦来支持分段可变的价值语义,如果它们从未被使用?虽然有些时候只有通过覆盖整个事物才能改变值类型是有意义的(例如'Double'或'Decimal'),有时候将一个集体意义附加到一组个别也有意义的变量。 – supercat 2013-04-22 23:16:46

+0

另外,术语“不可变结构”是一个用词不当。通过用'Struct2'中的相应字段的值覆盖其字段,语句“Struct1 = Struct2;'突变'Struct1'。 'Struct1'仍然会在分配之后引用*相同的实例*。即使所讨论的值类型声称是“不可变的”,装箱值类型实例始终具有可变引用语义,因为赋值,装箱和byref生成全部发生在类型的控制之外。 – supercat 2013-04-22 23:31:15