2012-01-03 9 views
6

Mam niestandardową sekcję konfiguracji zarejestrowaną w aplikacji/web.config, nazwijmy ją MySection. Wewnątrz sekcji znajduje się element ElementCollection o nazwie MyElements. W kolekcji elementów chcę mieć elementy reprezentowane przez różne klasy - chodzi o to, że są to podobne klasy z pewnymi wspólnymi właściwościami i niektórymi właściwymi dla instancji.Niestandardowa konfiguracja .NET - Czy mogę gromadzić elementy z niejednorodnymi elementami?

Oto przykład konfiguracji xml:

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

W moim prostym przykładzie, wszystkie elementy muszą mieć „name” własność, niektórzy będą mieć również właściwość „wartość”, a drugi „Format” własność. Tutaj chcę, aby Element1 i Element2 były reprezentowane w środowisku wykonawczym .NET przez dwie różne klasy, które mają wspólną klasę podstawową, która definiuje właściwość 'name'.

O ile zagłębiłem się w konfigurację .NET, odniosłem wrażenie, że kolekcja elementów (np. "MyElements" tutaj) powinna zawierać jednorodne elementy (tylko jednego typu). Tak więc, możliwe jest osiągnięcie tego, czego chcę - sprawić, by zawierały elementy różnych klas. Chodzi o to, aby uniknąć zarówno posiadania więcej niż jednej kolekcji elementów dla różnych typów elementów, jak i nie zapisywania wszystkich powtarzających się właściwości dla każdej niestandardowej implementacji ConfigurationElement.

Odpowiedz

8

Można to osiągnąć poprzez przesłonięcie metody OnDeserializeUnrecognizedElement w klasie ElementCollection i tworzenie reprezentacji Element1 i Element2 przez włączenie nazwy znacznika np. Jednak elementy potomne AFAIR powinny pochodzić od wspólnego przodka i tak robi się inaczej, to zbyt wiele problemów.

zdefiniować jako zbiór:

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

i elementem dziecko:

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

dziękuję za odpowiedź. Rzeczywiście, wspólny przodek jest tym, co i tak zamierzam użyć. Przynajmniej próbuję ponownie użyć wspólnych właściwości podobnych elementów, dlatego wspólny przodek może je przechowywać, a także zredukować kod dla konkretnych elementów :) –

Powiązane problemy