2012-01-17 5 views
1

У меня есть класс, который должен быть Singleton. Он также должен иметь возможность загружать и сохранять данные своего поля в 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

ответ

1

я использовал для запуска во все виды ошибок, что делает класс 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.

Таким образом, чтобы использовать это, вы, вероятно, напишите одноэлементный класс, который использует ваш класс non-singleton 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

Наличие класса Container как Singleton, который будет хранить личную ссылку на фактический объект, который мне интересен, кажется громоздким и ограничительный. Что делать, если я хочу перезагрузить «Настройки»? В этом случае в моем коде могут быть два экземпляра «Настройки», когда я перезагружаюсь из xml. –

Смежные вопросы