2016-01-20 62 views
0

我想序列化包含純數據的模型對象(來自WPF MVVM)。這聽起來很簡單,但我不想使用.NET Framework中提供的Serialization屬性和東西。我只是想用我自己的方式序列化它。
所以這裏是我的一個類的簡化版本。使用SOLID原則序列化自定義對象

public class EntryKeyValuePair 
{ 
    public EntryKeyValuePair(string key, string value, bool isMultiline = false, bool isMandatory = true, bool isProtected = false) 
    { 
     Key = key; 
     Value = value; 
     IsMultiline = isMultiline; 
     IsMandatory = isMandatory; 
     IsProtected = isProtected; 
    } 

    public string Key { get; set; } 
    public string Value { get; set; } 
    public bool IsMultiline { get; set; } 
    public bool IsMandatory { get; set; } 
    public bool IsProtected { get; set; } 

    public static EntryKeyValuePair FromXML(XElement element, ICipher cipher) 
    { 
     string key = cipher.Decrypt(element.Element(nameof(Key)).Value); 
     string value = cipher.Decrypt(element.Element(nameof(Value)).Value); 
     bool isMultiline = bool.Parse(element.Element(nameof(IsMultiline)).Value); 
     bool isMandatory = bool.Parse(element.Element(nameof(IsMandatory)).Value); 
     bool isProtected = bool.Parse(element.Element(nameof(IsProtected)).Value); 
     return new EntryKeyValuePair(key, value, isMultiline, isMandatory, isProtected); 
    } 

    public XElement ToXML(ICipher cipher) 
    { 
     return new XElement(nameof(EntryKeyValuePair), 
           new XElement(nameof(Key),cipher.Encrypt(Key)), 
           new XElement(nameof(Value), cipher.Encrypt(Value)), 
           new XElement(nameof(IsMultiline), IsMultiline), new XElement(nameof(IsMandatory), IsMandatory), 
           new XElement(nameof(IsProtected), IsProtected)); 
    } 
} 

這工作得很好。但這違反了單一責任原則,也可能違反其他原則。這也難以保持和擴展。
所以我想找到另一種方式。這裏是:

首先我定義了一個IStringFormatter接口,它可以將數據格式化爲任何字符串數據格式,如XML和JSON。 (不知道壽)

interface IStringFormatter 
{ 
    string Name { get; set; } 
    Dictionary<string, string> FieldDictionary { get; } 
    string Format(); 
} 

這裏的XMLStringFormatter的樣子:

class XmlStringFormatter : IStringFormatter 
{ 
    public XmlStringFormatter() 
    { 
     FieldDictionary = new Dictionary<string, string>(); 
    } 

    public string Name { get; set; } 
    public Dictionary<string, string> FieldDictionary { get; } 

    public string Format() 
    { 
     var xElement = new XElement(Name, FieldDictionary.Keys.Select(key => new XElement(key, FieldDictionary[key]))); 
     return xElement.ToString(); 
    } 
} 

然後,我定義的ISerializer序列化(或者說保存)我的數據對象的IStringFormatter

​​

這裏是我如何實施這個 「序列化」 EntryKeyValurPair

internal class EntryKeyValurPairSerializer : ISerializer<EntryKeyValuePair> 
{ 
    public EntryKeyValuePair DeSerialize(IStringFormatter stringFormatter) 
    { 
     Dictionary<string, string> fieldDictionary = stringFormatter.FieldDictionary; 

     try { 
      string key = fieldDictionary[nameof(EntryKeyValuePair.Key)]; 
      string value = fieldDictionary[nameof(EntryKeyValuePair.Value)]; 
      bool isMandatory = bool.Parse(fieldDictionary[nameof(EntryKeyValuePair.IsMandatory)]); 
      bool isProtected = bool.Parse(fieldDictionary[nameof(EntryKeyValuePair.IsProtected)]); 
      bool isMultiline = bool.Parse(fieldDictionary[nameof(EntryKeyValuePair.IsMultiline)]); 
      return new EntryKeyValuePair(key, value, isMultiline, isMandatory, isProtected); 
     } 
     catch (KeyNotFoundException ex) { 
      throw new SerializationException(ex); 
     } 
     catch (FormatException ex) { 
      throw new SerializationException(ex); 
     } 
    } 

    public void Serialize(EntryKeyValuePair obj, IStringFormatter stringFormatter) 
    { 
     stringFormatter.Name = nameof(EntryKeyValuePair); 
     Dictionary<string, string> fieldDictionary = stringFormatter.FieldDictionary; 

     fieldDictionary.Add(nameof(EntryKeyValuePair.Key), obj.Key); 
     fieldDictionary.Add(nameof(EntryKeyValuePair.Value), obj.Value); 
     fieldDictionary.Add(nameof(EntryKeyValuePair.IsMandatory), obj.IsMandatory.ToString()); 
     fieldDictionary.Add(nameof(EntryKeyValuePair.IsProtected), obj.IsProtected.ToString()); 
     fieldDictionary.Add(nameof(EntryKeyValuePair.IsMultiline), obj.IsMultiline.ToString()); 
    } 
} 

現在能正常工作。但問題是當我在我的數據類中有一個像List<Entry>(其中Entry是另一個數據類)的複雜類型時。
由於IStringFormatter包含Dictionary<string, string>,我不能只將List<Entry>轉換爲字符串,因爲我不知道它在ISerializer的上下文中想要什麼樣的IStringFormatter。我怎樣才能解決這個問題?我也想知道我的解決方案是否遵守SOLID原則。如果您可以提出更好的解決方案(不是典型的.NET序列化),我將不勝感激。

回答

2

編寫自己的序列化程序可能是一個有趣的任務,但我懷疑這是一個好主意。

據我所知,你想保持你的模型乾淨,沒有任何序列化的特定屬性。我認爲「典型的.NET序列化」是指.Net框架中包含的方法。

爲了簡單起見,我們將使用這些簡單的類爲例:

class Customer 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
    public List<Order> Orders { get; set; }  
} 

class Order 
{ 
    public int Id { get; set; } 
    public string Details { get; set; } 
} 

一個容易的選擇是使用Json.NET:

var customer = new Customer 
{ 
    Name = "Darth Vader", 
    Age = 45, 
    Orders = new List<Order> 
    { 
     new Order { Id = 1, Details = "Order1" }, 
     new Order { Id = 2, Details = "Order2" } 
    } 
}; 
string json = JsonConvert.SerializeObject(customer); 

所以你可以看到你不需要添加任何自定義屬性到Customer類。它會工作,直到你想序列化所有的公共屬性。

產生的JSON將是:

{ 
    "Name": "Darth Vader", 
    "Age": 45, 
    "Orders": [ 
    { 
     "Id": 1, 
     "Details": "Order1" 
    }, 
    { 
     "Id": 2, 
     "Details": "Order2" 
    } 
    ] 
} 

之後,你可以隨時反序列化:

var customer = JsonConvert.DeserializeObject<Customer>(json); 

比方說,你不希望被列入Age財產。在這種情況下,我會建議創建將只用於序列化不同的類:

class CostomerSerializationContract 
{ 
    public string Name { get; set; } 
    public List<Order> Orders { get; set; } 
} 

如果這種方法是,你必須系列化單獨的類,你可以添加任何自定義這主要優勢屬性那裏,如果您選擇使用其他序列化程序,而不違反SOLID原則。主要缺點是您需要手動同步兩個對象。

從源類創建序列化合約時,可以使用AutoMapper減少手動工作。

+0

這也適用於列表以及?它也有公開獲得,設置屬性 –

+0

是的,它會的。我在我的答案中添加了一個例子。 –

+0

如果我有一個'BitmapSource'(不能序列化)屬性呢? 。我可以將它轉換爲base64,但我怎麼能告訴序列化器做到這一點? –

相關問題