【问题标题】:How to store a dictionary in settings如何在设置中存储字典
【发布时间】:2019-07-07 08:29:41
【问题描述】:

我正在尝试编写可以存储在 app.config 或 web.config 文件中的通用字典。按照this answer中的例子,我写了一个字典,做了一些改动:

  1. 我使用了更现代的System.Xml.Linq API
  2. 我使用了 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


【解决方案1】:

尝试将您的stream 传递给 XmlReader 之类的

if (valueType != null)
{
    XmlSerializer xmlSerializer = new XmlSerializer(valueType);
    using (MemoryStream stream = new MemoryStream())
    {
        xmlSerializer.Serialize(stream, entry.Value);
        stream.Position = 0;

        using (XmlReader reader = XmlReader.Create(stream))
        {
            XElement valueXml = XElement.Load(reader);
            value = valueXml;
        }
    }
}

【讨论】:

  • 还是不行。还尝试使用来自另一个项目的类型。这次该类型出现在“浏览...”选项中,但仍然无效。
猜你喜欢
  • 2022-07-11
  • 1970-01-01
  • 2022-11-28
  • 2021-04-23
  • 2018-04-12
  • 2018-02-07
  • 1970-01-01
  • 2012-11-25
  • 2020-03-07
相关资源
最近更新 更多