English 中文(简体)
深度 XML 序列化一个结构体 Options
原标题:
  • 时间:2009-01-15 07:19:30
  •  标签:

I have the class and struct shown below. If I serialize the class as is using xmlserializer I get:

< Test>
< TestNumber1 >5< /TestNumber1 >
< InnerTest / >
< /Test >

what is the easiest way to make InnerTest serialise properly (preferably using xmlserializer) with out giving the Number property a setter?

Thanks, Nick

public class Test 
{ 
    private InnerTest innerTest; 
    private int testNumber; 


    public Test() 
    { 
        this.innerTest = new InnerTest(); 
        this.testNumber = 5; 
    } 


    public int TestNumber1 
    { 
        get { return this.testNumber; } 
        set { this.testNumber = value;} 
    } 


    public InnerTest InnerTest 
    { 
        get { return this.innerTest; } 
        set { this.innerTest = value;} 
    } 


} 


public struct InnerTest 
{ 
    private int number; 


    public InnerTest(int number) 
    { 
        this.number = number; 
    } 
    public int Number{get { return number; }} 
} 
问题回答

正如Jon Skeet所说,如果您不想为属性设置公共get/set,则需要使用IXmlSerializableXmlSerializer,因为它被设计为在部分受信任的环境中工作,因此不会访问任何您无法访问的数据(回答他最后一部分的问题,是的,有些结构体如DateTime在该序列化程序中具有显式支持)。

根据您要实现的功能和使用的.NET版本,您可以考虑使用,它不需要公开内容(例如,您可以在私有字段上放置或具有公共获取程序和私有设置程序的属性)。这种序列化程序使您对XML格式的控制较少(事实上,它非常受限制-例如,它甚至不支持属性!)但它也会更快。

我一直渴望着一种能够结合XmlSerializer的灵活性和能够序列化私有成员的DataContractSerializer的能力的东西,但目前还没有这样的东西。

如果在这种情况下可能的话,我会使用 DataContractSerializer (.NET 3.0),然后我会像这样使用:

[DataMember]
public int TestNumber1 
{ 
    get { return this.testNumber; } 
    set { this.testNumber = value;} 
} 

// note **not** a data-member
public InnerTest InnerTest 
{ 
    get { return this.innerTest; } 
    set { this.innerTest = value;} 
} 

[DataMember]
private int InnerTestValue
{
    get {return innerTest.Number;}
    set {innerTest = new InnerTest(value);}
}

这样就可以绕过这个问题。你也可以使用 XmlSerializer 进行类似的操作,但你需要将 InnerTestValue 设为 public(虽然你可以使用 [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 来装饰它,但这并不理想)。

当然,如果你的结构体具有多个值...就会更加棘手。你当然可以有多个shim属性,但这有点零散。基本上,[de]序列化和不可变对象(结构体应该是这样的)并不非常兼容。

另一个选择是维护一个使用可变类的单独POCO版本,并在两者之间进行转换;同样,对于大型对象模型来说,这不是一种非常吸引人的选择。

我从未亲自完成过,但我怀疑您只需要实现IXmlSerializable接口。

就我所知,这意味着您必须使您的结构可变 - 这很繁琐。理想情况下,XmlSerializer应该识别出您的类型是否具有特定签名的构造函数,但似乎这不是一个选项(就我所看到的而言),因此值得使用显式接口实现来至少防止用户直接使用它。

我想知道其他结构体(例如 DateTime)是如何管理的……也许它们在 XmlSerializer 中有显式的支持。

你可以在你的对象上确实使用 XmlSerializer 并获得预期结果:

Test test = new Test { TestNumber1 = 5 };

XmlSerializer xmlSer = new XmlSerializer(typeof(Test));
MemoryStream memStm = new MemoryStream();

xmlSer.Serialize(memStm, test);

为了验证结果,请再次将内存流读取为字符串,并在调试器中查看它(或将其写入文件)。

StreamReader stmR = new StreamReader(memStm);
memStm.Position = 0;
string output = stmR.ReadToEnd();

如果您不做任何特殊处理,您正在序列化的类的所有公共属性都将作为XML元素呈现.....在您的结果XML中。

有一堆属性可以进行调整,比如[XmlIgnore]等等,根据需要来调整。

享受!





相关问题
热门标签