2016-03-21 50 views
3

Son zamanlarda karmaşık (değişmez) yapılar içeren bir sınıfı serileştirmek zorunda kaldım. Bu işe gelene kadar başarısız oldum (bkz. ReadXml()). Doğru Aşağıdaki xml dosyasında okurBunu neden immutable bir `struct` yapabilirim?

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

:

Aşağıdaki kodu düşünün.

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

sorum nasıl içerikleri değişmez (readonly) anahtar kelime vardır this=new Point(new_x, new_y); eseridir nedir? Yapmamın içeriğini değiştiren

gibi üyeler eklemekten ne engeller?

{ 
     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 
    } 

bu beni okuma/XML dosyaları ile değişmez yapıların yazmasına olanak tanır çünkü bu işlevsellik mevcut sevindim, bunun işe yaradığını sadece çok şaşırtıcıdır.

+0

Yapılar ve sınıflar yapılar değişmez yapmak için en iyi yöntem olsa, varsayılan olarak değişmez değildir. –

+0

dolayısıyla "readonly" anahtar sözcüğü, özel alanlar ve yalnızca özelliklerdeki alıcılar. Tüm alanları, alanların üzerine yazılan ReadXml. – ja72

+1

Bu, birçok insan için şaşırtıcıdır. Http://joeduffyblog.com/2010/07/01/when-is-a-readonly-field-not-readonly/ –

cevap

2

Hiçbir şey sizi Reset yazmasını durdurmuyor. Aslında, bir sorun olmadan çalışacaktır.

Salt okunur anahtar kelime ile mümkündür, çünkü aslında yeni yapısını oluşturuyorsunuz, orijinali değiştirmiyorsunuz.

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 

Not newobj çağrı:

İşte kod ve oluşturulan IL bu. Eric Lippert olarak

koyar: 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

Yani yapı atomik ve değişmezdir. "Readonly" anahtar kelimesi varsa hiçbirini veya tamamını değiştirebilirsin. – ja72

+2

Blog makalemdeki linke aslında durumu açıklayan makaleye, linkin bozuk. Makale burada bulunabilir: http://joeduffyblog.com/2010/07/01/when-is-a-readonly-field-not-readonly/ –