2012-01-03 6 views
6

Tengo una sección de configuración personalizada registrada en la aplicación/web.config, llamémosla MySection. Tengo un elemento ElementCollection dentro de la sección, llamado MyElements. Dentro de la colección de elementos, quiero tener elementos que estén representados por diferentes clases, la idea es que estas son clases similares con algunas propiedades comunes y algunas específicas de la instancia.Configuración personalizada de .NET - ¿Puedo tener elementos de colección con elementos no homogéneos?

Aquí es un poco de ejemplo de configuración xml:

<MySection> 
    <MyElements> 
    <Element1 name="someProp1" value="someValue" /> 
    <Element2 name="someProp2" format="{0}{1}" /> 
    </MyElements> 
</MySection> 

En mi ejemplo sencillo, todos los elementos deben tener una propiedad 'nombre', algunos tendrán también una propiedad 'valor', y el otro un 'formato' propiedad. Aquí, quiero que Element1 y Element2 estén representados en el tiempo de ejecución de .NET por dos clases diferentes que tienen una clase base común que define la propiedad 'nombre'.

Por lo que he excavado en la configuración de .NET, tuve la impresión de que una colección de elementos (como 'MyElements' aquí) debería contener elementos homogéneos (solo de un tipo). Entonces, ¿podría ser posible lograr lo que quiero? Hacer que contenga elementos de diferentes clases. La idea es evitar tener más de una colección de elementos para diferentes tipos de elementos y no escribir todas las propiedades repetitivas para cada implementación personalizada de ConfigurationElement.

Respuesta

8

Puede lograr esto anulando el método OnDeserializeUnrecognizedElement en su clase ElementCollection y creando representaciones de su Element1 y Element2 activando el nombre de la etiqueta para ej. Pero los elementos secundarios de AFAIR deben derivarse de antepasados ​​comunes de todos modos, hacerlo de lo contrario es demasiado problema.

Definir colección como:

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; 
    } 
} 

Y elemento secundario:

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); 
    } 
} 
+0

Gracias por su respuesta. De hecho, un antepasado común es lo que quiero decir de todos modos. Al menos, estoy tratando de reutilizar las propiedades comunes de elementos similares, por lo tanto, el ancestro común puede almacenarlos y también reducir el código de los elementos concretos :) –

Cuestiones relacionadas