ConfigurationElementCollection con un número de ConfigurationElements de diferente tipo
-
29-10-2019 - |
Pregunta
Es posible tener un CollectionElementCollection con un número de diferentes según el tipo CollectionElements, por ejemplo:
<collection>
<add type="MyType1, MyLib" Type1SpecificProp="1" />
<add type="MyType2, MyLib" Type2SpecificProp="2" />
</collection
Tengo todos los cursos requeridos para dicha solución:
class MyCollection : ConfigurationElementCollection { }
class MyElement : ConfigurationElement { }
class MyType1 : MyElement { }
class MyType2 : MyElement { }
...
etc
pero cuando voy a iniciar mi aplicación me estoy poniendo de lado de predicción de error:
Atributo desconocido 'Type1SpecificProp'.
porque Type1SpecificProp
se define en MyType1
no MyElement
, especialmente si MyCollection
tiene método siguiente:
protected override ConfigurationElement CreateNewElement()
{
return new MyElement(); // but I want instantiate not the base class but by a type given
}
es decir,devuelve la clase base así OnDeserializeUnrecognizedAttribute()
en el niño clasificado nunca se ha llamado.
Así que la pregunta es:cómo vamos a clases hijas para resolver las incógnitas por su auto?
Solución 2
Microsoft.Practices.EnterpriseLibrary.Common.Configuration.PolymorphicConfigurationElementCollection<T>
de EntLib5 hace este trabajo como un encanto.
Otros consejos
También analicé esto. PolymorphicConfigurationElementCollection<T>
parece obsoleto .
Editar: no lo es, vea el comentario de 'abatishchev' a continuación, solo estaba vinculando una versión anterior.
La solución de Rest Wing fue prometedora, pero desafortunadamente requirió invocar métodos internos que residen en otro espacio de nombres. Si bien esto es posible mediante la reflexión, no recibirá precios por codificar belleza en este caso.
También indagué en la fuente con Reflection y se me ocurrió la siguiente solución:
[ConfigurationCollection(typeof(ElementBaseConfig), CollectionType=ConfigurationElementCollectionType.BasicMap)]
public class MyTypesConfigCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
// Not used but function must be defined
return null;
}
protected override object GetElementKey(ConfigurationElement element)
{
return element;
}
protected override ConfigurationElement CreateNewElement(string elementName)
{
switch (elementName)
{
case "mytype1":
return new MyType1Config();
case "mytype2":
return new MyType2Config();
default:
throw new ConfigurationErrorsException(
string.Format("Unrecognized element '{0}'.", elementName));
}
}
protected override bool IsElementName(string elementName)
{
// Required to be true
return true;
}
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMap; }
}
}
La anulación de CollectionType es OBLIGATORIA, incluso si esto se ha especificado a través del atributo en la parte superior. Cuando no se anula, la clase base 'CollectionType todavía se refiere a' AddRemoveClearMap 'que no activará la función requerida' CreateNewElement (string elementName) 'pero es una variante sin parámetros' CreateNemElement () '. Por la misma razón, la función IsElementName sobrescrita debería devolver verdadero.
Tenga en cuenta que creé un ElementBaseConfig que es la clase base de MyType1Config y MyType2Config en el que puede definir algunos atributos compartidos.
Una instancia de tipo específico (MyType1
y MyType2
) debe ser creado para que el niño las clases para resolver los elementos desconocidos o atributos por sí mismos.
Desde el CreateNewElement
método de no dar ningún tipo de información sobre un elemento atributos, que no es el lugar donde el tipo específico de la creación de instancias puede ocurrir.
Después de algo de investigación a través de Reflector, se llega a la siguiente parcial de la pila de llamadas:
VariantCollection.MyCollection.CreateNewElement()
System.Configuration.ConfigurationElementCollection.CallCreateNewElement()
System.Configuration.ConfigurationElementCollection.OnDeserializeUnrecognizedElement(string elementName, XmlReader reader)
El OnDeserializeUnrecognizedElement
el método puede ser anulada en MyCollection
clase con el fin de crear tipo específico de instancia.En lugar de utilizar el sin parámetros CallCreateNewElement
método, utilice uno nuevo que recibe XmlReader
:
- Leer el atributo
type
(de asegurar su existencia y validez). - Crear un nuevo elemento del tipo especificado.
- Llame
internal virtual void AssociateContext( BaseConfigurationRecord configRecord )
método deSystem.Configuration.ConfigurationElement
en el elemento. - Llame
internal void CallInit()
método deSystem.Configuration.ConfigurationElement
en el elemento. - Devolver el preparado elemento.
Por CIERTO, si no habrá demasiados diferentes elementos de colección, considere la posibilidad de usar algo como:
<myType1Collection>
<add Type1SpecificProp="1" />
</myType1Collection>
<myType2Collection>
<add Type2SpecificProp="2" />
</myType2Collection>
De esa manera usted puede evitar la proyección de los elementos de MyCollection
para el tipo específico.