2012-01-17 52 views
1

我有一個類需要是單例。 它還必須能夠加載並將其字段數據保存在xml文件中。使用xml編輯對象而不創建新的實例

以下方法將返回一個新的實例,這會破壞我的Singleton模式,在我的代碼中留下潛在的錯誤。

public Settings Load() 
{ 
    using (Stream stream = File.OpenRead(FileName)) 
    { 
    XmlSerializer serializer = new XmlSerializer(typeof(Settings)); 
    return (Settings)serializer.Deserialize(stream); 
    } 
} 

我可以使用什麼方法來更新現有實例中的數據,而不是返回一個全新的實例?

我已經研究了一下Linq到Xml,但還沒有找到任何好的例子。 是否有必要將我的所有字段數據保存在字典中?

+0

DI容器生命週期管理是通常比一個更好的選擇單身模式。請參閱http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons – TrueWill 2012-01-27 02:25:38

回答

1

我曾經碰到各種各樣的bug使得一個Xml Singleton類的,並最終殺它,因爲我已經處理了所有的地方。我用兩種方法取代了它。一個是用於讀取數據的只讀版本,另一個是用於寫入更改的使用方法/語句。

這一般是我使用的模式:我沒有用串行

public class Settings : IDisposable 
{ 
    string file = "my settings file"; 
    XElement root; 

    private Settings() 
    { 
     root = XElement.Load(file);   
    } 

    private void Dispose() 
    { 
     root.Save(file); 
    } 

    public static Settings Read { get { return new Settings(); } } // return read-only version 

    public static void Write(Action<Settings> handler) 
    { 
     using(Setting settings = new Settings()) 
      handler(settings); 
    } 

    // below here is implentation specific 

    public XElement Root { get { return root; } } 

    public string SettingA 
    { 
     get { return (string)(Root.Attribute("SettingA") ?? (object)string.Empty); } 
     set { Set(Root, "SettingsA", value, true); } 
    } 

    // I wrote this for another StackOverflow thread 
    /// <summary> 
    /// Set any value via its .ToString() method. 
    /// <para>Returns XElement of source or the new XElement if is an ELEMENT</para> 
    /// </summary> 
    /// <param name="isAttribute">true for ATTRIBUTE or false for ELEMENT</param> 
    /// <returns>source or XElement value</returns> 
    private XElement Set(XElement source, string name, object value, bool isAttribute) 
    { 
     string sValue = value.ToString(); 
     XElement eValue = source.Element(name), result = source; 
     XAttribute aValue = source.Attribute(name); 
     if (null != eValue) 
      eValue.ReplaceWith(result = new XElement(name, sValue)); 
     else if (null != aValue) 
      aValue.ReplaceWith(new XAttribute(name, sValue)); 
     else if (isAttribute) 
      source.Add(new XAttribute(name, sValue)); 
     else 
      source.Add(result = new XElement(name, sValue)); 
     return result; 
    } 

    /// <summary> 
    /// Replace with for XAttribute 
    /// </summary> 
    /// <param name="source"></param> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static XAttribute ReplaceWith(this XAttribute source, XAttribute value) 
    { 
     XElement parent = source.Parent; 
     if (null == parent) 
      throw new Exception("Source has no parent"); 
     source.Remove(); 
     parent.Add(value); 
     return value; 
    } 

} 

,所以不知道是不是我的模式會適合你。我更喜歡XElement。

所以要使用它,你可能會寫一個使用非單例XmlSerialize類的單例類。你只能通過單例訪問它。

但是,這是我怎麼會最終使用它作爲是:

string settingA = Settings.Read.SettingA; 

要保存的值將是:

Settings.Write(s => s.SettingA = "new value"); 
0

你爲什麼不有類似

public Class TheClassHoldingYourObject 
{ 
    private static XmlSerializer _instance; 
    public static Settings Load() 
    { 
     if(_instance != null) return _instance 
     using (Stream stream = File.OpenRead(FileName)) 
     { 
       XmlSerializer serializer = new XmlSerializer(typeof(Settings)); 
       return (Settings)serializer.Deserialize(stream); 
     } 
    } 
} 

現在,你總是會得到相同的實例

+0

有一個容器類作爲一個單身人士,將保持對我感興趣的實際對象的私人引用似乎很笨拙,限制。 如果我想重新加載我的「設置」,該怎麼辦?在這種情況下,當我從xml重新加載時,我的代碼中可能有兩個「設置」實例。 – 2012-01-17 12:00:46