我必须在应用程序设置中存储复杂类型。我认为将其存储为XML最有效。
问题是我不知道如何存储XML。我更喜欢将它存储为托管XML,而不是只使用一串原始XML,必须在每次访问时解析它。我设法将设置的Type
列设置为XDocument,但我无法设置其值。
有没有办法在应用程序设置中使用XDocument或XML?
更新
我找到了一种方法,只需使用xml编辑器编辑.settings文件。
我将其更改为custom serializable dictionary,但是当我尝试访问setting-property时,我收到以下错误(我将其设置为默认值的序列化表示形式)。
The property 'Setting' could not be created from it's default value.
Error message: There is an error in XML document (1, 41).
任何想法都将受到赞赏。
答案 0 :(得分:2)
我所做的(即使我不喜欢这么多 - 但是有效)是:
我创建了我的值的简单可序列化类:
<Xml.Serialization.XmlRoot("Rooms")> _
Public Class Rooms : Inherits List(Of Room)
End Class
<Serializable()> _
Public Class Room
Private m_Room As String
Public Property Room() As String
Get
Return m_Room
End Get
Set(ByVal value As String)
m_Room = value
End Set
End Property
Private m_Sections As New List(Of Section)
Public ReadOnly Property Sections() As List(Of Section)
Get
Return m_Sections
End Get
End Property
End Class
<Serializable()> _
Public Class Section
Private m_Section As String
Public Property Section() As String
Get
Return m_Section
End Get
Set(ByVal value As String)
m_Section = value
End Set
End Property
End Class
然后在.settings文件中,我将设置的类型(使用xml编辑器打开的.setting文件)编辑为Rooms的全名(即MyProject.Rooms)。 然后我自己做了一个反序列化的示例样本,并将其复制到.settings编辑器中的value字段,以获得默认值。它很棒。 它确实不是字典,但我仍然可以在Rooms类和内部字典中实现(通过Room.Room返回Sections。
任何好的想法仍然受到欢迎,我仍在寻找一种方法,可以在.settings文件中使用IDictinoary
。
此外,我为它开了connection,请善待并投票!
答案 1 :(得分:2)
我最终做的是因为这是阻力最小的路径是使用.NET Fx中的内置配置类。即使以下代码在C#中,您也应该能够轻松地将其转换为VB.NET(或者编辑并将其编译为可以从项目中引用的程序集)。
您将注意到ConfigurationElementCollection类可以很容易地转换为键/值对的字典(您可能必须对值对使用反射,或者您希望存储的类作为值对可以采用设置类,从ConfigurationElement继承为构造函数参数)。
// ConfigurationElement.cs
public class ConfigurationElement : System.Configuration.ConfigurationElement
{
protected T GetValue<T>(string key, T defaultValue)
{
var value = default(T);
if (base[key] != null)
{
var str = base[key].ToString();
try
{
if (!String.IsNullOrEmpty(str))
value = (T)Convert.ChangeType(str, typeof(T));
}
catch // use the default
{
}
}
return value;
}
}
// ConfigurationElementCollection.cs
public abstract class ConfigurationElementCollection<TElement,TKey> :
ConfigurationElementCollection,
IEnumerable<TElement> where TElement : System.Configuration.ConfigurationElement, new()
{
public TElement this[int index]
{
get { return (TElement)BaseGet(index); }
}
public TElement this[TKey key]
{
get { return (TElement)BaseGet(key); }
}
protected override System.Configuration.ConfigurationElement CreateNewElement()
{
return new TElement();
}
protected override object GetElementKey(System.Configuration.ConfigurationElement element)
{
return GetElementKey((TElement)element);
}
protected abstract TKey GetElementKey(TElement element);
public TKey[] GetAllKeys()
{
var keys = BaseGetAllKeys();
var ret = new TKey[keys.Length];
for (var i = 0; i < keys.Length; i++)
ret[i] = (TKey)keys[i];
// done
return ret;
}
public void Add(TElement element)
{
BaseAdd(element);
}
public void Remove(TElement element)
{
BaseRemove(element);
}
public void Clear()
{
BaseClear();
}
IEnumerator<TElement> IEnumerable<TElement>.GetEnumerator()
{
foreach (TElement element in this)
{
yield return element;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new System.NotImplementedException();
}
}
这是一个例子,我在我们的系统中使用上面的基类代码进行分片策略(名称被修改以保护无辜者):
<!-- web.config -->
<!-- ... -->
<configuration>
<configSections>
<section name="sharding" type="Domain.ShardingSection, Domain.Configuration" />
</configSections>
</configuration>
<!-- ... -->
<sharding>
<configurationMappings>
<add lastDigit="0" sqlMapFileName="Shard-0.SqlMap.config" />
<add lastDigit="1" sqlMapFileName="Shard-1.SqlMap.config" />
<add lastDigit="2" sqlMapFileName="Shard-2.SqlMap.config" />
<add lastDigit="3" sqlMapFileName="Shard-3.SqlMap.config" />
<add lastDigit="4" sqlMapFileName="Shard-4.SqlMap.config" />
<add lastDigit="5" sqlMapFileName="Shard-5.SqlMap.config" />
<add lastDigit="6" sqlMapFileName="Shard-6.SqlMap.config" />
<add lastDigit="7" sqlMapFileName="Shard-7.SqlMap.config" />
<add lastDigit="8" sqlMapFileName="Shard-8.SqlMap.config" />
<add lastDigit="9" sqlMapFileName="Shard-9.SqlMap.config" />
</configurationMappings>
</sharding>
然后是上面的XML实例所代表的配置类:
// ShardElement.cs
public class ShardElement : ConfigurationElement
{
[ConfigurationProperty("lastDigit", IsKey=true, IsRequired=true)]
public int LastDigit
{
get { return (int)this["lastDigit"]; }
}
[ConfigurationProperty("sqlMapFileName", IsRequired=true)]
public string SqlMapFileName
{
get { return (string)this["sqlMapFileName"]; }
}
}
// ShardElementCollection.cs
public class ShardElementCollection : ConfigurationElementCollection<ShardElement, int>
{
protected override int GetElementKey(ShardElement element)
{
return element.LastDigit;
}
}
// ShardingSection.cs
public class ShardingSection : ConfigurationSection
{
public const string Name = "sharding";
[ConfigurationProperty("configurationMappings")]
public ShardingElementCollection ConfigurationMappings
{
get { return (ShardingElementCollection)base["configurationMappings"]; }
}
}
虽然它在* .config文件中不是真正的IDictionary,但它可以处理作业,如果您的配置文件在运行时更新,则不必重新启动应用程序或回收AppPool以获取新值。