编辑与XML对象,而无需创建新实例 [英] Edit Object with xml without creating new Instance

查看:99
本文介绍了编辑与XML对象,而无需创建新实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个必须是一个Singleton类。
它还必须能够装载和保存在一个XML文件中的字段数据。



下面的方法将返回一个新的实例,它打破我的Singleton模式,留在我的代码中潜在的错误。

 使用(流流的公共设置的load()
{
= File.OpenRead(文件名))
{
XmlSerializer的序列化=新的XmlSerializer(typeof运算(设置));
回报(设置)serializer.Deserialize(流);
}
}



我可以以更新数据用什么方法在我现有的实例,而不是返回一个全新的实例?



我研究了一下的LINQ到XML,但没有发现这有什么好的例子。
是我有必要保持我的所有现场数据字典?


解决方案

我以前碰到的所有

错误使得一个Xml Singleton类的种类和最终报废它,因为我不得不处理所有的地方。我用两种方式取而代之。一个只读版本,这是用于读取数据,并且用于写入的变化的第二使用方法/语句。



这一般是我使用的模式:

 公共类设置:IDisposable的
{
字符串文件=我的设置文件;
的XElement根;

私人设置()
{
根= XElement.Load(文件);
}

私人无效的Dispose()
{
root.Save(文件);
}

公共静态设置读取{{返回新设置(); }} //返回只读版本

公共静态无效的写(动作<设置>处理)使用
{
(设置设置=新设置())
处理器(设置);
}

//下面这里是implentation具体

公众的XElement根{{返回根; }}

公共字符串SettingA
{
{返回(字符串)(Root.Attribute(SettingA)??(对象)的String.Empty); }
集合{集(根,SettingsA,值为true); }
}

//我写这篇另一个线程计算器
///<总结>
///将通过它的ToString()方法中的任何值。
///&下;第>返回源或者如果是一个元素<新的XElement的的XElement; /段>
///< /总结>
///< PARAM NAME =则isAttribute>如此属性或假的元素< /参数>
///<退货和GT;源或价值的XElement和LT; /回报>
私人的XElement组(源的XElement,字符串名称,对象的值,布尔则isAttribute)
{
S值的字符串= value.ToString();
的XElement安勤= source.Element(名称),结果=来源;
XAttribute安勤= source.Attribute(名);
如果(空=安勤!)
eValue.ReplaceWith(结果=新的XElement(姓名,S值));
,否则如果(空=安勤!)
aValue.ReplaceWith(新XAttribute(姓名,S值));
,否则如果(则isAttribute)
source.Add(新XAttribute(姓名,S值));
,否则
source.Add(结果=新的XElement(姓名,S值));
返回结果;
}

///<总结>
///替换为对XAttribute
///< /总结>
///< PARAM NAME =源>< /参数>
///< PARAM NAME =值>< /参数>
///<&回报GT;< /回报>
公共静态XAttribute ReplaceWith(此XAttribute源,XAttribute值)
{
的XElement父= source.Parent;
如果(空==父)
抛出新的异常(源没有父);
source.Remove();
parent.Add(值);
返回值;
}

}



我没有用串行,所以不知道是不是我的模式将适合你。我更喜欢的XElement。



因此​​,要使用这个,你可能会写一个单独的类,使您使用非单XMLSERIALIZE类。你只是想通过单访问



但是,这是我怎么会最终使用它作为是:



 字符串settingA = Settings.Read.SettingA; 

要保存的值将是:



  Settings.Write(S = GT; s.SettingA =新价值); 


I have a class which needs to be a Singleton. It must also be able to load and save its field data in an xml file.

The following method will return a new instance, which breaks my Singleton pattern, leaving potential bugs in my code.

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

What method can I use in order to update the data in my existing instance, instead of returning a entirely new instance?

I've studied a bit of Linq to Xml, but haven't found any good example of this. Is it necessary for me to keep all my field data in a Dictionary?

解决方案

I used to run into all sorts of bugs making an Xml Singleton class and ended up scrapping it as I had handles all over the place. I replaced it with using two ways. One a read-only version that was for reading data, and a second Using method/statement for writing changes.

This in general is the pattern I use:

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;
    }

}

I've not used the serializer, so don't know if my pattern will fit for you. I prefer XElement.

So to use this you'd probably write a singleton class that makes use of your non-singleton XmlSerialize class. You'd only access it through the singleton.

But this is how I'd end up using it as is:

string settingA = Settings.Read.SettingA;

To save a value it would be:

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

这篇关于编辑与XML对象,而无需创建新实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆