序列化自定义配置
Serializing custom configuration
我需要一些帮助来实现序列化自定义配置的方法。我从以下示例的内容开始:Polymorphic custom configuration section
读取配置工作正常,但我无法保存对某些配置属性的修改(例如,将 属性 P1 更改为包含另一个字符串)。虽然调试不同对象的内容看起来不错(部分包含集合,其中包含三个代理项,这些代理项本身包含一个 Parent class 的实例)。已更改的项目 (P1="") 的 isModified 标志设置为 true(如预期)。
调用 config.Save() 时出现一些奇怪的行为,经过三天的调查(即使是 Microsoft base classes)我也无法找出问题所在。以下是我的一些结论:
我为每个 SerializeX 方法(SerializeSection、SerializeElement 和 SerializeToXmlElement)添加了一个覆盖,并通过代码逐步调试。
SerializeSection 被调用(如预期的那样),参数 parentElement 是 而不是 我想序列化为的部分Collection 属性 是空的(我希望它有三个实例,它们是配置文件的一部分)。使用 this 而不是 parentElement 调用 base.SerializeSection 解决了问题
SerializeToXmlElement 在 SerializeElement 之前调用并且确实包含 XmlWriter 的实例(如预期的那样)
SerializeElement 在 SerializeToXmlElement 之后被调用并且不 包含不再是 XmlWriter 的实例
当进入集合对象的序列化方法时,我希望集合的三个元素被序列化。但是该集合只包含一个新初始化的项目,而不是这三个项目,因此有一个 Parent 属性 返回 null.
我知道需要有一个自定义的 SerializeElement 方法(可能在代理 class 上)然后调用 _Parent.ProxySerializeElement(writer, serializeCollectionKey)对于每个元素,就像反序列化一样。但我无法让它发挥作用。 SerializeElement 的覆盖不起作用,因为 XmlWriter 实例始终为 null(即使 Proxy class 有一些 IsModified 方法来检查 Parent 对象是否已更改)。此外,只要我输入此自定义 SerializeElement 方法,Parent 对象也始终为 null。
以下是我添加到示例中的代码片段:
Parent.cs
new public bool IsModified { get { return IsModified(); } }
public virtual bool ProxySerializeElement(XmlWriter writer, bool serializeCollectionKey)
{
return SerializeElement(writer, serializeCollectionKey);
}
Proxy.cs
protected override bool IsModified()
{
bool isModified = base.IsModified();
return isModified || (Parent == null ? false : Parent.IsModified);
}
protected override bool SerializeElement(XmlWriter writer, bool serializeCollectionKey)
{
bool serialize = base.SerializeElement(writer, serializeCollectionKey);
return serialize || (_Parent == null ? false : _Parent.ProxySerializeElement(writer, serializeCollectionKey));
}
它无法正常工作,这让我抓狂。也许其他人可以帮助我。
提前致谢!
你好,Stefi
最后这对我有用。也许它可以帮助遇到同样问题的其他人。为了简单起见,我将 post 完整的代码。它可能不是第一个 class 解决方案,但它确实有效。如果其他人可以查看它并提出更好的方法,我将不胜感激。
帮助我让它工作的是这篇文章:https://www.codeproject.com/Articles/16466/Unraveling-the-Mysteries-of-NET-2-0-Configuration
我的代码缺少元素集合(参见 ThingElement.cs)。
thing.config
<configuration>
<configSections>
<section name="ExampleSection" type="ConsoleApplication1.Things.ExampleSection, ConsoleApplication1" />
</configSections>
<ExampleSection>
<things>
<thing type="one" name="one-1" color="green" />
<thing type="one" name="one-2" color="red" />
<thing type="two" name="two-1" />
</things>
</ExampleSection>
</configuration>
ExampleSection.cs
public class ExampleSection : ConfigurationSection
{
static ExampleSection() { }
[ConfigurationProperty("things")]
[ConfigurationCollection(typeof(ThingElement), AddItemName = "thing",
CollectionType = ConfigurationElementCollectionType.BasicMap)]
public ExampleThingElementCollection Things
{
get { return (ExampleThingElementCollection)this["things"]; }
set { this["things"] = value; }
}
}
ExampleThingElementCollection.cs
[ConfigurationCollection(typeof(ThingElement), AddItemName = "thing",
CollectionType = ConfigurationElementCollectionType.BasicMap)]
public class ExampleThingElementCollection : ConfigurationElementCollection
{
#region Constructors
public ExampleThingElementCollection()
{
}
#endregion
#region Properties
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMap; }
}
protected override string ElementName
{
get { return "thing"; }
}
#endregion
#region Indexers
public ThingElement this[int index]
{
get { return (ThingElement)base.BaseGet(index); }
set
{
if (base.BaseGet(index) != null)
{
base.BaseRemoveAt(index);
}
base.BaseAdd(index, value);
}
}
new public ThingElement this[string name]
{
get { return (ThingElement)base.BaseGet(name); }
}
#endregion
#region Overrides
protected override ConfigurationElement CreateNewElement()
{
return new ThingElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return (element as ThingElement).Name;
}
#endregion
#region Methods
public void Add(ThingElement thing)
{
base.BaseAdd(thing);
}
public void Remove(string name)
{
base.BaseRemove(name);
}
public void Remove(ThingElement thing)
{
base.BaseRemove(GetElementKey(thing));
}
public void Clear()
{
base.BaseClear();
}
public void RemoveAt(int index)
{
base.BaseRemoveAt(index);
}
public string GetKey(int index)
{
return (string)base.BaseGetKey(index);
}
#endregion
}
ThingElement.cs(这个class作为代理元素)
public class ThingElement : ConfigurationElement
{
#region Constructors
/// <summary>
/// Predefines the valid properties and prepares
/// the property collection.
/// </summary>
static ThingElement()
{
// Predefine properties here
s_propName = new ConfigurationProperty(
"name",
typeof(string),
null,
ConfigurationPropertyOptions.IsRequired
);
}
#endregion
#region Static Fields
private static ConfigurationProperty s_propName;
private static Dictionary<string, SpecialThing> elements = new Dictionary<string, SpecialThing>();
#endregion
#region Properties
/// <summary>
/// Gets the Name setting.
/// </summary>
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get { return (string)base[s_propName]; }
}
public SpecialThing Thing { get { return elements[Name]; } }
protected override bool SerializeElement(XmlWriter writer, bool serializeCollectionKey)
{
return Thing.ProxySerializeElement(writer, serializeCollectionKey);
}
protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey)
{
SpecialThing obj = null;
string name = reader.GetAttribute("name");
string type = reader.GetAttribute("type");
switch (type)
{
case "one":
obj = new One();
break;
case "two":
obj = new Two();
break;
default:
throw new ArgumentException(string.Format("Invalid type: {0}", type));
}
base[s_propName] = name;
if (!elements.ContainsKey(name))
elements.Add(name, obj);
obj.ProxyDeserializeElement(reader, serializeCollectionKey);
}
private Hashtable attributes;
public Hashtable Attributes
{
get
{
if (attributes == null)
attributes = new Hashtable(StringComparer.OrdinalIgnoreCase);
return attributes;
}
}
protected override bool OnDeserializeUnrecognizedAttribute(String name, String value)
{
Attributes.Add(name, value);
return true;
}
protected override void PreSerialize(XmlWriter writer)
{
if (attributes != null)
{
IDictionaryEnumerator e = attributes.GetEnumerator();
while (e.MoveNext())
{
string xmlValue = (string)e.Value;
string xmlName = (string)e.Key;
if ((xmlValue != null) && (writer != null))
{
writer.WriteAttributeString(xmlName, xmlValue);
}
}
}
}
#endregion
}
SpecialThing.cs(父级 class,例如基础 class 如果你有其他派生)
public class SpecialThing : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get
{
return (string)this["name"];
}
set
{
this["name"] = value;
}
}
[ConfigurationProperty("type", IsRequired = true)]
public string Type
{
get
{
return (string)this["type"];
}
set
{
this["type"] = value;
}
}
public virtual bool ProxySerializeElement(XmlWriter writer, bool serializeCollectionKey)
{
return SerializeElement(writer, serializeCollectionKey);
}
public void ProxyDeserializeElement(XmlReader reader, bool serializeCollectionKey)
{
DeserializeElement(reader, serializeCollectionKey);
}
}
One.cs(父 class,例如基础 class 如果你有其他派生
public class One : SpecialThing
{
public One() { }
public One(string name, string type, string color)
{
base.Name = name;
base.Type = type;
Color = color;
}
[ConfigurationProperty("color")]
public string Color
{
get { return (string)this["color"]; }
set { this["color"] = value; }
}
}
Two.cs
public class Two : SpecialThing
{
public Two() { }
public Two(string name, string type)
{
base.Name = name;
base.Type = type;
}
}
我需要一些帮助来实现序列化自定义配置的方法。我从以下示例的内容开始:Polymorphic custom configuration section
读取配置工作正常,但我无法保存对某些配置属性的修改(例如,将 属性 P1 更改为包含另一个字符串)。虽然调试不同对象的内容看起来不错(部分包含集合,其中包含三个代理项,这些代理项本身包含一个 Parent class 的实例)。已更改的项目 (P1="") 的 isModified 标志设置为 true(如预期)。
调用 config.Save() 时出现一些奇怪的行为,经过三天的调查(即使是 Microsoft base classes)我也无法找出问题所在。以下是我的一些结论:
我为每个 SerializeX 方法(SerializeSection、SerializeElement 和 SerializeToXmlElement)添加了一个覆盖,并通过代码逐步调试。
SerializeSection 被调用(如预期的那样),参数 parentElement 是 而不是 我想序列化为的部分Collection 属性 是空的(我希望它有三个实例,它们是配置文件的一部分)。使用 this 而不是 parentElement 调用 base.SerializeSection 解决了问题
SerializeToXmlElement 在 SerializeElement 之前调用并且确实包含 XmlWriter 的实例(如预期的那样)
SerializeElement 在 SerializeToXmlElement 之后被调用并且不 包含不再是 XmlWriter 的实例
当进入集合对象的序列化方法时,我希望集合的三个元素被序列化。但是该集合只包含一个新初始化的项目,而不是这三个项目,因此有一个 Parent 属性 返回 null.
我知道需要有一个自定义的 SerializeElement 方法(可能在代理 class 上)然后调用 _Parent.ProxySerializeElement(writer, serializeCollectionKey)对于每个元素,就像反序列化一样。但我无法让它发挥作用。 SerializeElement 的覆盖不起作用,因为 XmlWriter 实例始终为 null(即使 Proxy class 有一些 IsModified 方法来检查 Parent 对象是否已更改)。此外,只要我输入此自定义 SerializeElement 方法,Parent 对象也始终为 null。
以下是我添加到示例中的代码片段:
Parent.cs
new public bool IsModified { get { return IsModified(); } }
public virtual bool ProxySerializeElement(XmlWriter writer, bool serializeCollectionKey)
{
return SerializeElement(writer, serializeCollectionKey);
}
Proxy.cs
protected override bool IsModified()
{
bool isModified = base.IsModified();
return isModified || (Parent == null ? false : Parent.IsModified);
}
protected override bool SerializeElement(XmlWriter writer, bool serializeCollectionKey)
{
bool serialize = base.SerializeElement(writer, serializeCollectionKey);
return serialize || (_Parent == null ? false : _Parent.ProxySerializeElement(writer, serializeCollectionKey));
}
它无法正常工作,这让我抓狂。也许其他人可以帮助我。
提前致谢!
你好,Stefi
最后这对我有用。也许它可以帮助遇到同样问题的其他人。为了简单起见,我将 post 完整的代码。它可能不是第一个 class 解决方案,但它确实有效。如果其他人可以查看它并提出更好的方法,我将不胜感激。
帮助我让它工作的是这篇文章:https://www.codeproject.com/Articles/16466/Unraveling-the-Mysteries-of-NET-2-0-Configuration
我的代码缺少元素集合(参见 ThingElement.cs)。
thing.config
<configuration>
<configSections>
<section name="ExampleSection" type="ConsoleApplication1.Things.ExampleSection, ConsoleApplication1" />
</configSections>
<ExampleSection>
<things>
<thing type="one" name="one-1" color="green" />
<thing type="one" name="one-2" color="red" />
<thing type="two" name="two-1" />
</things>
</ExampleSection>
</configuration>
ExampleSection.cs
public class ExampleSection : ConfigurationSection
{
static ExampleSection() { }
[ConfigurationProperty("things")]
[ConfigurationCollection(typeof(ThingElement), AddItemName = "thing",
CollectionType = ConfigurationElementCollectionType.BasicMap)]
public ExampleThingElementCollection Things
{
get { return (ExampleThingElementCollection)this["things"]; }
set { this["things"] = value; }
}
}
ExampleThingElementCollection.cs
[ConfigurationCollection(typeof(ThingElement), AddItemName = "thing",
CollectionType = ConfigurationElementCollectionType.BasicMap)]
public class ExampleThingElementCollection : ConfigurationElementCollection
{
#region Constructors
public ExampleThingElementCollection()
{
}
#endregion
#region Properties
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMap; }
}
protected override string ElementName
{
get { return "thing"; }
}
#endregion
#region Indexers
public ThingElement this[int index]
{
get { return (ThingElement)base.BaseGet(index); }
set
{
if (base.BaseGet(index) != null)
{
base.BaseRemoveAt(index);
}
base.BaseAdd(index, value);
}
}
new public ThingElement this[string name]
{
get { return (ThingElement)base.BaseGet(name); }
}
#endregion
#region Overrides
protected override ConfigurationElement CreateNewElement()
{
return new ThingElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return (element as ThingElement).Name;
}
#endregion
#region Methods
public void Add(ThingElement thing)
{
base.BaseAdd(thing);
}
public void Remove(string name)
{
base.BaseRemove(name);
}
public void Remove(ThingElement thing)
{
base.BaseRemove(GetElementKey(thing));
}
public void Clear()
{
base.BaseClear();
}
public void RemoveAt(int index)
{
base.BaseRemoveAt(index);
}
public string GetKey(int index)
{
return (string)base.BaseGetKey(index);
}
#endregion
}
ThingElement.cs(这个class作为代理元素)
public class ThingElement : ConfigurationElement
{
#region Constructors
/// <summary>
/// Predefines the valid properties and prepares
/// the property collection.
/// </summary>
static ThingElement()
{
// Predefine properties here
s_propName = new ConfigurationProperty(
"name",
typeof(string),
null,
ConfigurationPropertyOptions.IsRequired
);
}
#endregion
#region Static Fields
private static ConfigurationProperty s_propName;
private static Dictionary<string, SpecialThing> elements = new Dictionary<string, SpecialThing>();
#endregion
#region Properties
/// <summary>
/// Gets the Name setting.
/// </summary>
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get { return (string)base[s_propName]; }
}
public SpecialThing Thing { get { return elements[Name]; } }
protected override bool SerializeElement(XmlWriter writer, bool serializeCollectionKey)
{
return Thing.ProxySerializeElement(writer, serializeCollectionKey);
}
protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey)
{
SpecialThing obj = null;
string name = reader.GetAttribute("name");
string type = reader.GetAttribute("type");
switch (type)
{
case "one":
obj = new One();
break;
case "two":
obj = new Two();
break;
default:
throw new ArgumentException(string.Format("Invalid type: {0}", type));
}
base[s_propName] = name;
if (!elements.ContainsKey(name))
elements.Add(name, obj);
obj.ProxyDeserializeElement(reader, serializeCollectionKey);
}
private Hashtable attributes;
public Hashtable Attributes
{
get
{
if (attributes == null)
attributes = new Hashtable(StringComparer.OrdinalIgnoreCase);
return attributes;
}
}
protected override bool OnDeserializeUnrecognizedAttribute(String name, String value)
{
Attributes.Add(name, value);
return true;
}
protected override void PreSerialize(XmlWriter writer)
{
if (attributes != null)
{
IDictionaryEnumerator e = attributes.GetEnumerator();
while (e.MoveNext())
{
string xmlValue = (string)e.Value;
string xmlName = (string)e.Key;
if ((xmlValue != null) && (writer != null))
{
writer.WriteAttributeString(xmlName, xmlValue);
}
}
}
}
#endregion
}
SpecialThing.cs(父级 class,例如基础 class 如果你有其他派生)
public class SpecialThing : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get
{
return (string)this["name"];
}
set
{
this["name"] = value;
}
}
[ConfigurationProperty("type", IsRequired = true)]
public string Type
{
get
{
return (string)this["type"];
}
set
{
this["type"] = value;
}
}
public virtual bool ProxySerializeElement(XmlWriter writer, bool serializeCollectionKey)
{
return SerializeElement(writer, serializeCollectionKey);
}
public void ProxyDeserializeElement(XmlReader reader, bool serializeCollectionKey)
{
DeserializeElement(reader, serializeCollectionKey);
}
}
One.cs(父 class,例如基础 class 如果你有其他派生
public class One : SpecialThing
{
public One() { }
public One(string name, string type, string color)
{
base.Name = name;
base.Type = type;
Color = color;
}
[ConfigurationProperty("color")]
public string Color
{
get { return (string)this["color"]; }
set { this["color"] = value; }
}
}
Two.cs
public class Two : SpecialThing
{
public Two() { }
public Two(string name, string type)
{
base.Name = name;
base.Type = type;
}
}