2014-02-28 177 views
3

在我們的應用程序中,我們有一個Money類型,它包含一個金額(十進制)和一個貨幣代碼(字符串)。在簡單的形式,它看起來像這樣:實現複合數據類型的自定義XML序列化/反序列化?

public class Money 
{ 
    public decimal Amount{get;set;} 
    public string CurrencyCode{get;set;} 
} 

正如你可能想象,這在應用中有許多地方被使用,因爲它是從客戶端發送到/經常是序列化/反序列化。貨幣金額通常被序列化爲複合值,例如, 「1.23美元」代表1.23美元。舊客戶端(HTML/JS)會將該值解析爲其組成部分,並返回Money類型。錢值作爲元素值發送,並作爲屬性值,取決於它們在應用程序,如其中:

<SomeClass moneyValue="1.23USD" ... /> 

<SomeClass> 
<MoneyValue>1.23USD</MoneyValue> 
... 
</SomeClass> 

我試圖找出一種方式,我可以使用內置的C#/ .NET Xml序列化工具來實現這種相同的行爲。我着眼於實現ISerializable,但一直未能弄清楚這樣做的正確方法。

本質上,我希望能夠通過我自己的自定義邏輯(知道如何將「1.23USD」解析爲貨幣數量)反序列化貨幣數量,並將其序列化爲簡單字符串。 「1.23USD」

的最終目標將是能夠在一個類中的貨幣量或者:

[XmlAttribute] 
public Money SomeField // SomeField='123.USD 

或:

[XmlElement] 
public Money SomeOtherField //<SomeOtherField>1.23USD</SomeOtherField> 

用同樣的方法,你可以這樣做簡單類型如int,string,double等。

這可能嗎?

+0

如何創建一些格式化你想要的公共字符串屬性?然後像你一樣使用XML序列化器。將原始字段設置爲[XmlIgnore]。如果要保留現有類型,只需使用一個包裝類,將包裝類的成員公開爲公共屬性。 – Baldrick

回答

1

下面的代碼做的伎倆:

public class Money 
{ 
    public decimal Amount { get; set; } 
    public string CurrencyCode { get; set; } 
} 

public class SomeClass 
{ 
    public SomeClass() { } 

    [XmlIgnore] 
    public Money WrappedMoney { get; set; } 

    [XmlAttribute] 
    public string moneyValue 
    { 
     get 
     { 
      return String.Format("{0:.##}{1}", WrappedMoney.Amount, WrappedMoney.CurrencyCode); 
     } 
    } 

} 

public class ParentClass 
{ 
    public SomeClass SomeClass {get; set;} 
} 

class Program 
{ 
    public static int Main(string[] args) 
    { 
     var parent = new ParentClass 
     { 
      SomeClass = new SomeClass 
      { 
       WrappedMoney = new Money { Amount = 1.25M, CurrencyCode = "USD" } 
      } 
     }; 

     var serializer = new XmlSerializer(typeof(ParentClass)); 

     using (var writer = new StreamWriter("output.xml")) 
     { 
      serializer.Serialize(writer, parent); 
     } 

     return 0; 
    } 
} 

XML輸出是:

<?xml version="1.0" encoding="utf-8"?> 
<ParentClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <SomeClass moneyValue="1.25USD" /> 
</ParentClass> 
3

原來真的沒有一個很好的100%的回答這個 - 問題是,你可以將複雜類型(例如Money)序列化爲屬性,即使將其序列化爲簡單的字符串。所以無論如何,我不能擁有一般可以重用的someAttribute ='1.23 USD'。

所以...發佈的答案是屬性的一個很好的解決方法,對於我用Money作爲元素的地方,我只實現了IXmlSerializable來輸出複合字段並在解析時重新分割它。這樣,不需要包裝,它只是工作。

public struct Money : IXmlSerializable 
    { 
     public double Amount { get; set; } 
     public string CurrencyCode { get; set; } 

     public System.Xml.Schema.XmlSchema GetSchema() 
     { 
      return (null); 
     } 

     public void ReadXml(System.Xml.XmlReader reader) 
     { 
      reader.MoveToContent(); 

      Boolean isEmptyElement = reader.IsEmptyElement; // (1) 
      reader.ReadStartElement(); 
      if (!isEmptyElement) // (1) 
      { 
       var str = reader.ReadContentAsString(); 
       string[] sa = str.Split(' '); 
       Amount = double.Parse(sa[0]); 
       CurrencyCode = sa[1]; 
       reader.ReadEndElement(); 
      } 
     } 

     public void WriteXml(System.Xml.XmlWriter writer) 
     { 
      writer.WriteString(Amount + " " + CurrencyCode); 
     } 
    } 

而對於屬性,發佈的答案也適用,謝謝。