具有多个不同类型的 ConfigurationElement 的 ConfigurationElementCollection
是否可以拥有一个具有许多不同类型 CollectionElements 的 CollectionElementCollection,例如:
<collection>
<add type="MyType1, MyLib" Type1SpecificProp="1" />
<add type="MyType2, MyLib" Type2SpecificProp="2" />
</collection
我拥有此类解决方案所需的所有类:
class MyCollection : ConfigurationElementCollection { }
class MyElement : ConfigurationElement { }
class MyType1 : MyElement { }
class MyType2 : MyElement { }
...
etc
但是当我启动我的应用程序时,我会收到下一个可预测的错误:
无法识别的属性“Type1SpecificProp”。
因为 Type1SpecificProp
是在 MyType1
中定义的,而不是在 MyElement
中定义的,特别是如果 MyCollection
有 next 方法:
protected override ConfigurationElement CreateNewElement()
{
return new MyElement(); // but I want instantiate not the base class but by a type given
}
即返回基类,因此 <子类中的 code>OnDeserializeUnrecognizedAttribute() 从未被调用。
那么问题来了:如何让子类自己解决未知元素呢?
Is it possible to have a CollectionElementCollection with a number of different by type CollectionElements, e.g.:
<collection>
<add type="MyType1, MyLib" Type1SpecificProp="1" />
<add type="MyType2, MyLib" Type2SpecificProp="2" />
</collection
I have all classes required for such solution:
class MyCollection : ConfigurationElementCollection { }
class MyElement : ConfigurationElement { }
class MyType1 : MyElement { }
class MyType2 : MyElement { }
...
etc
but when I start my application I'm getting next predictable error:
Unrecognized attribute 'Type1SpecificProp'.
because Type1SpecificProp
is defined in MyType1
not MyElement
, especially if MyCollection
has next method:
protected override ConfigurationElement CreateNewElement()
{
return new MyElement(); // but I want instantiate not the base class but by a type given
}
i.e. returns base class thus OnDeserializeUnrecognizedAttribute()
in child classed are never been called.
So the question is: how to let child classes to resolve unknown elements by their self?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我也调查了这一点。
PolymorphicConfigurationElementCollection
似乎已弃用。编辑:不是,请参阅下面“abatishchev”的评论,我只是链接旧版本。
Rest Wing 的解决方案很有希望,但不幸的是需要调用驻留在另一个命名空间中的内部方法。虽然这可以通过反射实现,但在这种情况下,它不会因为编码美观而付出代价。
我也用 Reflection 深入研究了源代码,并提出了以下解决方案:
CollectionType 的重写是必需的,即使这是通过顶部的属性指定的。当不重写基类时,CollectionType 仍然引用“AddRemoveClearMap”,它不会触发所需的“CreateNewElement(string elementName)”函数,但它是无参数变体“CreateNemElement()”。出于同样的原因,覆盖的 IsElementName 函数应该返回 true。
请注意,我创建了一个 ElementBaseConfig,它是 MyType1Config 和 MyType2Config 的基类,您可以在其中定义一些共享属性。
I looked into this as well.
PolymorphicConfigurationElementCollection<T>
seems deprecated.Edit: it's not, see the comment of 'abatishchev' below, i was just linking an old version.
The solution of Rest Wing was promising but unfortunately required invoking internal methods residing in another namespace. While this is possible via reflection it isn't going to receive prices for coding beauty in this case.
I digged into the source with Reflection too and came up with the following solution:
The override of the CollectionType is REQUIRED, even if this has been specified via the attribute in the top. When not overridden the base class' CollectionType still refers to 'AddRemoveClearMap' which isn't going to trigger the required 'CreateNewElement(string elementName)' function but it's parameterless variant 'CreateNemElement()'. For the same reason the overwritten IsElementName function should return true.
Note that I created a ElementBaseConfig which is the base class of both MyType1Config and MyType2Config in which you could define some shared attributes.
来自 EntLib5 的
Microsoft.Practices.EnterpriseLibrary.Common.Configuration.PolymorphicConfigurationElementCollection
可以作为一个魅力来完成这项工作。Microsoft.Practices.EnterpriseLibrary.Common.Configuration.PolymorphicConfigurationElementCollection<T>
from EntLib5 do this job as a charm.需要创建特定类型(
MyType1
和MyType2
)的实例,以便子类能够自行解析未知元素或属性。由于
CreateNewElement
方法不提供有关元素属性的任何信息,因此这不是可以发生特定类型实例化的地方。通过 Reflector 进行一些挖掘后,我们得到以下部分调用堆栈:
可以在
MyCollection
类中重写OnDeserializeUnrecognizedElement
方法,以便创建特定类型实例。不要使用无参数CallCreateNewElement
方法,而是使用接收XmlReader
:type
的新方法(确保其存在和有效性)。System.Configuration.ConfigurationElement
的内部 virtual void AssociateContext( BaseConfigurationRecord configRecord )
方法。System.Configuration.ConfigurationElement
的internal void CallInit()
方法。顺便说一句,如果不会有太多不同的集合元素,请考虑使用类似的方法:
这样您就可以避免将项目从
MyCollection
转换为特定类型。An instance of specific type (
MyType1
andMyType2
) needs to be created in order for child classes to resolve unknown elements or attributes by themselves.Since the
CreateNewElement
method does not give any information on an element's attributes, that is not place where specific type instantiation can occur.After some digging via Reflector, one comes to following partial call stack:
The
OnDeserializeUnrecognizedElement
method can be overriden inMyCollection
class in order to create specific type instance. Instead of using the parameterlessCallCreateNewElement
method, use new one that receivesXmlReader
:type
(ensure its existence and validity).internal virtual void AssociateContext( BaseConfigurationRecord configRecord )
method ofSystem.Configuration.ConfigurationElement
on the element.internal void CallInit()
method ofSystem.Configuration.ConfigurationElement
on the element.BTW, if there will not be too many different collection elements, consider using something like:
That way you can avoid casting the items from
MyCollection
to specific type.