ConfigurationElementCollection с несколькими ConfigurationElements разного типа
-
29-10-2019 - |
Вопрос
Возможно ли иметь CollectionElementCollection с несколькими различными по типу CollectionElements, например:
<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
имеет следующий метод:
protected override ConfigurationElement CreateNewElement()
{
return new MyElement(); // but I want instantiate not the base class but by a type given
}
т. е.возвращает базовый класс таким образом OnDeserializeUnrecognizedAttribute()
в дочерних классах они никогда не вызывались.
Итак, вопрос заключается в следующем:как разрешить дочерним классам самостоятельно разрешать неизвестные элементы?
Решение 2
Microsoft.Practices.EnterpriseLibrary.Common.Configuration.PolymorphicConfigurationElementCollection<T>
из EntLib5 отлично справляется с этой задачей.
Другие советы
Я тоже занимался этим. PolymorphicConfigurationElementCollection<T>
кажется устаревшим .
Изменить: это не так, см. Комментарий abatishchev ниже, я просто связывал старую версию.
Решение Rest Wing было многообещающим, но, к сожалению, требовало вызова внутренних методов, находящихся в другом пространстве имен. Хотя это возможно с помощью отражения, в этом случае плата за кодирование красоты не взимается.
Я тоже покопался в источнике с помощью Reflection и нашел следующее решение:
родовое словоТРЕБУЕТСЯ переопределение CollectionType, даже если это было указано через атрибут вверху. Если базовый класс не переопределен, CollectionType по-прежнему ссылается на AddRemoveClearMap, который не будет запускать требуемую функцию CreateNewElement (string elementName), а это вариант без параметров CreateNemElement (). По той же причине перезаписанная функция IsElementName должна возвращать значение true.
Обратите внимание, что я создал ElementBaseConfig, который является базовым классом как MyType1Config, так и MyType2Config, в котором вы можете определять некоторые общие атрибуты.
Экземпляр определенного типа (MyType1
и MyType2
) необходимо создать для того, чтобы дочерние классы могли сами разрешать неизвестные элементы или атрибуты.
С тех пор, как CreateNewElement
метод не предоставляет никакой информации об атрибутах элемента, то есть это не то место, где может произойти создание экземпляра определенного типа.
После некоторого копания с помощью Reflector можно прийти к следующему частичному стеку вызовов:
VariantCollection.MyCollection.CreateNewElement()
System.Configuration.ConfigurationElementCollection.CallCreateNewElement()
System.Configuration.ConfigurationElementCollection.OnDeserializeUnrecognizedElement(string elementName, XmlReader reader)
Тот Самый OnDeserializeUnrecognizedElement
метод может быть переопределен в MyCollection
класс для того, чтобы создать экземпляр определенного типа.Вместо использования параметра без параметров CallCreateNewElement
метод, используйте новый, который получает XmlReader
:
- Атрибут чтения
type
(обеспечить его существование и действительность). - Создайте новый элемент указанного типа.
- Звонить
internal virtual void AssociateContext( BaseConfigurationRecord configRecord )
способ полученияSystem.Configuration.ConfigurationElement
об элементе. - Звонить
internal void CallInit()
способ полученияSystem.Configuration.ConfigurationElement
об элементе. - Верните подготовленный элемент.
Кстати, если не будет слишком много разных элементов коллекции, рассмотрите возможность использования чего-то вроде:
<myType1Collection>
<add Type1SpecificProp="1" />
</myType1Collection>
<myType2Collection>
<add Type2SpecificProp="2" />
</myType2Collection>
Таким образом, вы можете избежать приведения элементов из MyCollection
к определенному типу.