使用xml编辑对象而不创建新实例

时间:2012-01-17 11:27:21

标签: c# xml linq singleton linq-to-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,但没有找到任何好的例子。 我是否有必要将所有现场数据保存在字典中?

2 个答案:

答案 0 :(得分:1)

我曾经遇到过制作Xml Singleton类的各种错误,并且最终报废了,因为我已经处理了整个地方。我用两种方式替换它。一个用于读取数据的只读版本,另一个用于写入更改的Using方法/语句。

这通常是我使用的模式:

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");

答案 1 :(得分: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); 
        } 
    }
 }

现在,您将始终获得相同的实例