.NET configuration. Can I have a collection of elements with heterogeneous elements?

I have a custom configuration section registered in app / web.config, call it MySection . I have an ElementCollection element inside a section called MyElements . Inside the collection of elements, I want to have elements that are represented by different classes. The idea is that these are similar classes with some common properties and some instance-specific ones.

Here is an example xml configuration:

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

In my simple example, all elements must have a 'name' property, some will also have a 'value' property, and another will have a 'format' property. Here, I want Element1 and Element2 appear in the .NET runtime as two different classes that share a common base class that defines the name property.

As far as I fit into the .NET configuration, I got the impression that the collection of elements (for example, "MyElements" here) should contain homogeneous elements (of only one type). So, is it possible to achieve what I want - to make it contain elements of different classes. The idea is to avoid collecting multiple elements for different types of elements, and not to write all duplicate properties for each custom implementation of ConfigurationElement .

+6
source share
1 answer

You can do this by overriding the OnDeserializeUnrecognizedElement method in your ElementCollection class and creating views of your Element1 and Element2 by including the tag name for ex. But AFAIR child elements must be obtained from a common ancestor anyway, otherwise it's too much.

Define the collection as:

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

And child element:

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

Source: https://habr.com/ru/post/904985/


All Articles