2016-03-21 2 views
3

最近、複雑な(不変の)構造を含むクラスを直列化しなければなりませんでした。私はこれを考え出すまで失敗し続けました(ReadXml()参照)。正しく次のXMLファイルを読み込みなぜこれを不変の `struct`にすることができますか?

[ImmutableObject(true)]  
public struct Point : IXmlSerializable 
{ 
    readonly int x, y; 

    public Point(int x, int y) 
    { 
     this.x=x; 
     this.y=y; 
    } 
    public Point(Point other) 
    { 
     this=other; 
    } 
    public int X { get { return x; } } 
    public int Y { get { return y; } } 

    public System.Xml.Schema.XmlSchema GetSchema() 
    { 
     return null; 
    } 
    public void ReadXml(System.Xml.XmlReader reader) 
    { 
     // Immutable, right? 
     int new_x =0, new_y=0; 
     int.TryParse(reader.GetAttribute("X"), out new_x); 
     int.TryParse(reader.GetAttribute("Y"), out new_y); 
     // But I can change the contents by assigning to 'this' 
     this=new Point(new_x, new_y); 
    } 
    public void WriteXml(System.Xml.XmlWriter writer) 
    { 
     writer.WriteAttributeString("X", X.ToString()); 
     writer.WriteAttributeString("Y", Y.ToString()); 
    } 
} 

public class Foo 
{ 
    Point from, to; 
    public Foo() { } 
    public Foo(Point from, Point to) 
    { 
     this.from=from; 
     this.to=to; 
    } 
    public Point From { get { return from; } set { from=value; } } 
    public Point To { get { return to; } set { to=value; } } 
} 

は、次のコードを考えてみましょう。

<?xml version="1.0" encoding="utf-8"?> 
<Foo> 
    <From X="100" Y="30" /> 
    <To X="45" Y="75" /> 
</Foo> 

私の質問はどのように内容が不変(readonly)キーワードですthis=new Point(new_x, new_y);仕事があるのですか?何が私の構造の内容を変えるようなメンバーの追加から私を止めているのですか?

public void Reset() 
    { 
     this=new Point(0, 0); 
    } 
    public void Add(Point other) 
    { 
     this=new Point(x+other.x, y+other.y); 
    } 

{ 
     Point foo=new Point(10, 15); 
     // foo.X=10, foo.Y=15 
     Point bar=new Point(foo); // Clone 
     // bar.X=10, bar.Y=15 

     foo.Reset(); 
     // foo.X=0, foo.Y=0 

     bar.Add(bar); 
     // bar.X=20, bar.Y=30 
    } 

が、私はそれは私が読み取り/ XMLファイルを不変の構造を記述することができますので、この機能が存在して嬉しい、動作することだけでは非常に驚くべきことです。

+0

構造体とクラスは、デフォルトでは不変ではありません。 –

+0

したがって 'readonly'キーワード、プライベートフィールド、およびプロパティのgetterのみです。すべて、フィールドを上書きする 'ReadXml'を除いて。 – ja72

+1

これは多くの人にとって驚くべきことです。 http://joeduffyblog.com/2010/07/01/when-is-a-readonly-field-not-readonly/ –

答えて

2

何も書いてもらえません。Reset事実、問題なく動作します。

実際に構造体構造体が作成されているため、readonlyキーワードで可能ですが、元の構造体は変更していません。

public void Reset() 
{ 
    this = new Point(0,0); 
} 

IL_0000: nop   
IL_0001: ldarg.0  
IL_0002: ldc.i4.0  
IL_0003: ldc.i4.0  
IL_0004: newobj  UserQuery+Point..ctor 
IL_0009: stobj  UserQuery.Point 
IL_000E: ret 

newobjコール:

は、ここでは、コードと生成されたILです。 Eric Lippertとして

はそれを置く:構造体を不変にする最善の方法ですが、Basically, “readonly” fields in a struct are the moral equivalent of the struct author writing a cheque without having the funds to back it.

+0

構造体はアトミックで不変です。 'readonly'キーワードがあれば、何も変更しなくても変更できます。 – ja72

+2

実際に状況を説明する記事への私のブログ記事のリンクは、そのリンクが壊れています。この記事はここにあります:http://joeduffyblog.com/2010/07/01/when-is-a-readonly-field-not-readonly/ –

関連する問題