【发布时间】:2019-07-07 08:29:41
【问题描述】:
我正在尝试编写可以存储在 app.config 或 web.config 文件中的通用字典。按照this answer中的例子,我写了一个字典,做了一些改动:
- 我使用了更现代的
System.Xml.LinqAPI - 我使用了 Hashtable,它允许我存储任何类型的值,只要它是可序列化的,而不仅仅是字符串。
[SettingsSerializeAs(SettingsSerializeAs.Xml)]
public class XmlSerializableDictionary : Hashtable, IXmlSerializable
{
#region Constructors
/// <summary>
/// Initializes a new instance of <see cref="XmlSerializableDictionary"/>.
/// </summary>
public XmlSerializableDictionary()
{
}
#endregion
#region IXmlSerializable Members
/// <inheritdoc />
public XmlSchema GetSchema()
{
return null;
}
/// <inheritdoc />
public void ReadXml(XmlReader reader)
{
XDocument xdoc = XDocument.Load(reader);
foreach (XElement entry in xdoc.Elements())
{
XElement key = entry.Element(nameof(DictionaryEntry.Key))
?? throw new FormatException($"{nameof(DictionaryEntry.Key)} is missing in entry");
XElement valueElement = entry.Element(nameof(DictionaryEntry.Value))
?? throw new FormatException($"{nameof(DictionaryEntry.Value)} element is missing in entry");
XAttribute valueTypeName = valueElement?.Attribute("type") ?? throw new FormatException($"type attribute is missing in {nameof(DictionaryEntry.Value)} element");
if (valueTypeName.Value == "null")
{
this[key.Value] = null;
}
else
{
Type valueType = Type.GetType(valueTypeName.Value);
XmlSerializer xmlSerializer = new XmlSerializer(valueType ?? throw new ArgumentException("type attribute value is not a valid type name."));
Object value = xmlSerializer.Deserialize(valueElement.CreateReader());
this[key.Value] = value;
}
}
}
/// <inheritdoc />
public void WriteXml(XmlWriter writer)
{
XDocument xdoc = new XDocument();
xdoc.Add(new XElement(nameof(XmlSerializableDictionary)));
foreach (DictionaryEntry entry in this)
{
Type valueType = entry.Value?.GetType();
String typeName = valueType == null ? "null" : $"{valueType.FullName}, {valueType.Assembly.GetName().Name}";
Object value = null;
if (valueType != null)
{
XmlSerializer xmlSerializer = new XmlSerializer(valueType);
using (MemoryStream stream = new MemoryStream())
{
xmlSerializer.Serialize(stream, entry.Value);
using (StreamReader reader = new StreamReader(stream))
{
stream.Seek(0, SeekOrigin.Begin);
String xmlString = reader.ReadToEnd();
XElement valueXml = XElement.Load(xmlString);
value = valueXml;
}
}
}
XElement entryElement = new XElement(nameof(DictionaryEntry),
new XElement(nameof(DictionaryEntry.Key),
new XAttribute("type", typeName),
entry.Key.ToString()),
new XElement(nameof(DictionaryEntry.Value), value));
xdoc.Root?.Add(entryElement);
}
}
#endregion
/// <inheritdoc />
public override void Add(object key, object value)
{
if (!(key is String))
{
throw new NotSupportedException($"{nameof(key)} must be a string.");
}
base.Add(key, value);
}
}
预期的 XML 架构应该是
<XmlSerializableDictionary>
<DictionaryEntry>
<Key>Key1</Key>
<Value type="System.Int32"> <!-- example type-->
Value1
</Value>
</DictionaryEntry>
<!--other entries here -->
</XmlSerializableDictionary>
但是,在设置设计器中添加此类型的设置和示例值后,该设置不会写入实现此设置的类库的 app.config 文件。我有什么遗漏吗?
更新 我将上面的 XML 更新如下,但还是不行:
<?xml version="1.0" encoding="utf-16"?>
<XmlSerializableDictionary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DictionaryEntry>
<Key>Key1</Key>
<Value type="System.Int32">42</Value>
</DictionaryEntry>
</XmlSerializableDictionary>
【问题讨论】:
-
好电话。我无法让字符串数组工作,即使它有一个类型。
-
@TaW StringCollection 非常适合。
-
经过数小时令人沮丧的工作后,我放弃了这一点,转而将字符串数组填充到一个字符串中。呃。我想看看一个真正有效的例子。我发现的只是(通常是相互矛盾的)帖子,这些帖子展示了人们应该使用的各种技巧(!)。没有人在这里工作:-(
标签: c# xml app-config