我在 app/web.config 中注册了一个自定义配置部分,我们称它为 MySection
。我在该部分中有一个 ElementCollection
元素,称为 MyElements
。在元素集合中,我希望拥有由不同类表示的元素 - 我的想法是,这些类是相似的类,具有一些公共(public)属性和一些特定于实例的属性。
这里是一些xml配置的例子:
<MySection>
<MyElements>
<Element1 name="someProp1" value="someValue" />
<Element2 name="someProp2" format="{0}{1}" />
</MyElements>
</MySection>
在我的简单示例中,所有元素都必须具有“名称”属性,一些元素还具有“值”属性,而其他元素则具有“格式”属性。
在这里,我希望 Element1
和 Element2
在 .NET 运行时中由两个不同的类表示,这两个类具有定义“名称”属性的公共(public)基类。
就我深入研究 .NET 配置而言,我的印象是元素集合(如此处的“MyElements”)应该包含同类元素(仅一种类型)。那么,是否有可能实现我想要的——让它包含不同类的元素。这个想法是为了避免为不同的元素类型使用多个元素集合,并且不要为每个自定义 ConfigurationElement
实现编写所有重复属性。
最佳答案
您可以通过覆盖 ElementCollection 类中的 OnDeserializeUnrecognizedElement 方法并通过打开 ex 的标记名称来创建 Element1 和 Element2 的表示来实现此目的。但是无论如何,AFAIR 子元素都应该派生自共同祖先,否则就太麻烦了。
定义集合为:
public class MyElementCollection : ConfigurationElementCollection
{
const string ELEMENT1 = "Element1";
const string ELEMENT2 = "Element2";
protected override ConfigurationElement CreateNewElement ()
{
return new MyElement (this);
}
protected override object GetElementKey (ConfigurationElement element)
{
return ((MyElement)element).Key;
}
// This method called when framework sees unknown element tag
// inside the collection. You can choose to handle it yourself
// and return true, or return false to invoke default action
// (exception will be thrown).
protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader)
{
if (elementName == ELEMENT1 || elementName == ELEMENT2 {
var myElement = new MyElement (this);
switch (elementName) {
case ELEMENT1:
myElement.Type = MyElementType.Element1;
break;
case ELEMENT2:
myElement.Type = MyElementType.Element2;
break;
}
myElement.DeserializeElementForConfig (reader, false);
BaseAdd (myElement);
return true;
}
return false;
}
}
和子元素:
public enum MyElementType
{
Element1,
Element2,
}
public class MyElement : ConfigurationElement
{
const string NAME = "name";
const string VALUE = "value";
const string FORMAT = "format";
// keys should be unique, current collection count will do
// the trick without introducing artificial keys
public MyElement (ConfigurationElementCollection collection)
{
Key = collection.Count;
}
// note that this is not ConfigurationProperty
public int Key { get; private set; }
// note that this is not ConfigurationProperty
public MyElementType Type { get; set; }
[ConfigurationProperty(NAME)]
public string Name {
get { return (string)this [NAME]; }
}
[ConfigurationProperty(VALUE)]
public string Value {
get { return (string)this [VALUE]; }
}
[ConfigurationProperty(FORMAT)]
public string Format {
get { return (string)this [FORMAT]; }
}
// This is called when framework needs a copy of the element,
// but it knows only about properties tagged with ConfigurationProperty.
// We override this to copy our Key and Type, otherwise they will
// have default values.
protected override void Reset (ConfigurationElement parentElement)
{
base.Reset (parentElement);
var myElement = (MyElement)parentElement;
Key = myElement.Key;
Type = myElement.Type;
}
// original ConfigurationElement have this protected,
// redeclaring as protected internal to call it from collection class
protected internal void DeserializeElementForConfig (XmlReader reader, bool serializeCollectionKey)
{
DeserializeElement (reader, serializeCollectionKey);
}
}
关于c# - .NET 自定义配置 - 我可以拥有包含非同类元素的元素集合吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8713356/