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?

¿Fue útil?

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:

  1. Leer el atributo type (de asegurar su existencia y validez).
  2. Crear un nuevo elemento del tipo especificado.
  3. Llame internal virtual void AssociateContext( BaseConfigurationRecord configRecord ) método de System.Configuration.ConfigurationElement en el elemento.
  4. Llame internal void CallInit() método de System.Configuration.ConfigurationElement en el elemento.
  5. 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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top