Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3026_IntegrationIntoSymSpace/HeuristicLab.JsonInterface/Converters/ConfigurableConverter.cs @ 17371

Last change on this file since 17371 was 17371, checked in by dpiringe, 4 years ago

#3026:

  • added new Converters:
    • CheckedItemListConverter
    • ItemCollectionConverter
    • PrimitiveConverter: not implemented yet
    • ConfigurableConverter: maybe this converter can replace all others
  • added program for testing -> HeuristicLab.ConfigStarter
  • added the option to register converter with an attic guid
File size: 7.3 KB
Line 
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Linq;
5using System.Reflection;
6using System.Text;
7using System.Threading.Tasks;
8using HeuristicLab.Core;
9
10
11using DefaultValueCb = System.Func<object>;
12using RangeCb = System.Func<object[]>;
13using ExtractCb = System.Func<object, System.Type, System.Collections.Generic.IEnumerable<HeuristicLab.JsonInterface.JsonItem>>;
14
15namespace HeuristicLab.JsonInterface {
16
17  /*
18   * Converter der mit Hilfe einer Konfiguration einen Typen
19   * konvertieren kann. In einer Konfiguration sollten (als String)
20   * die Properties/Fields stehen, welche er zur Umwandlung benutzt.
21   * Wenn nur ein Property/Field konfiguriert ist, wird ein einfaches
22   * JsonItem erstellt. Bei mehreren Properties/Fields werden diese
23   * Daten als Parameter eingefügt.
24   *
25   */
26
27  public enum ElementType { None, Property, Field }
28
29  public class ConfigurableConverter : BaseConverter {
30    public class Config {
31      public string ElementName { get; set; }
32      public ElementType ElementType { get; set; }
33      public DefaultValueCb DefaultValue { get; set; }
34      public RangeCb Range { get; set; }
35      public ExtractCb Extract { get; set; }
36    }
37
38    private const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
39   
40    private IDictionary<string, Config> PConfigs { get; set; }
41      = new Dictionary<string, Config>();
42
43    private IDictionary<string, Config> FConfigs { get; set; }
44      = new Dictionary<string, Config>();
45
46    private IList<Config> TConfigs { get; set; } = new List<Config>();
47
48
49    public ConfigurableConverter Primitive(string elementName, ElementType elementType, object defaultValue, params object[] range) =>
50      Primitive(elementName, elementType, () => defaultValue, () => range);
51
52    public ConfigurableConverter Primitive(string elementName, ElementType elementType, DefaultValueCb defaultValue) =>
53      Primitive(elementName, elementType, defaultValue, () => new object[] { });
54
55    public ConfigurableConverter Primitive(string elementName, ElementType elementType, DefaultValueCb defaultValue, RangeCb range) =>
56      Add(elementName, elementType, defaultValue, range, (o,t) => {
57        if (!t.IsPrimitive)
58          throw new InvalidCastException($"Type {t.Name} is not a primitive type!");
59        return new JsonItem[] {
60          new JsonItem() {
61            Name = elementName,
62            Value = o,
63            Range = range().Length == 0 ?
64              new object[] { GetMinValue(t), GetMaxValue(t) } :
65              range()
66          }
67        };
68      });
69
70    public ConfigurableConverter IItem(string elementName, DefaultValueCb defaultValue, RangeCb range, ElementType elementType) =>
71      Add(elementName, elementType, defaultValue, range, (o,t) => {
72        if (!t.IsEqualTo(typeof(IItem)))
73          throw new InvalidCastException($"Type {t.Name} is not an IItem!");
74        return new JsonItem[] {
75          JsonItemConverter.Extract(o as IItem)
76        };
77      });
78
79    public ConfigurableConverter Enumerable(string elementName, ElementType elementType, ExtractCb extract) =>
80      Add(elementName, elementType, null, null, (o,t) => {
81        if (!t.IsEqualTo(typeof(IEnumerable)))
82          throw new InvalidCastException($"Type {t.Name} is not an IEnumerable!");
83        return extract(o,t);
84      });
85
86    public ConfigurableConverter PrimitiveEnumerable(string elementName, ElementType elementType, object defaultValue) =>
87      PrimitiveEnumerable(elementName, elementType, () => defaultValue);
88
89    public ConfigurableConverter PrimitiveEnumerable(string elementName, ElementType elementType, DefaultValueCb defaultValue) =>
90      Add(elementName, elementType, defaultValue, null, (o,t) => {
91        if (!t.IsEqualTo(typeof(IEnumerable)))
92          throw new InvalidCastException($"Type {t.Name} is not an IEnumerable!");
93
94        return new JsonItem[] {
95            new JsonItem() {
96              Name = elementName,
97              Value = o != null ? o : defaultValue()
98            }
99          };
100      });
101
102    public ConfigurableConverter This(ExtractCb extract) =>
103      Add(null, ElementType.None, null, null, extract);
104
105    public ConfigurableConverter Add(string elementName, ElementType elementType, DefaultValueCb defaultValue, RangeCb range, ExtractCb extract)
106      => Add(new Config() { ElementName = elementName,
107                            ElementType = elementType,
108                            DefaultValue = defaultValue,
109                            Range = range,
110                            Extract = extract
111                          });
112
113    public ConfigurableConverter Add(Config config) {
114      switch(config.ElementType) {
115        case ElementType.None:
116          TConfigs.Add(config);
117          break;
118        case ElementType.Field:
119          FConfigs.Add(config.ElementName, config);
120          break;
121        case ElementType.Property:
122          PConfigs.Add(config.ElementName, config);
123          break;
124      }
125      return this;
126    }
127
128    public override JsonItem ExtractData(IItem value) {
129      List<JsonItem> parameters = new List<JsonItem>();
130      Type type = value.GetType();
131
132      // Properties
133      parameters.AddRange(IterateMemberInfo(value, type.GetProperties(flags), s => {
134        return PConfigs.TryGetValue(s, out Config c) ? c : null;
135      }));
136
137      // Fields
138      parameters.AddRange(IterateMemberInfo(value, type.GetFields(flags), s => {
139        return FConfigs.TryGetValue(s, out Config c) ? c : null;
140      }));
141
142      // This Calls
143      foreach (var c in TConfigs)
144        parameters.AddRange(c.Extract(value, value.GetType()));
145
146      JsonItem item = new JsonItem() {
147        Parameters = parameters,
148        Path = value.ItemName,
149        Type = type.AssemblyQualifiedName
150      };
151
152      item.UpdatePath();
153
154      return item;
155    }
156
157    public override void InjectData(IItem item, JsonItem data) {
158      throw new NotImplementedException();
159    }
160
161    private IEnumerable<JsonItem> IterateMemberInfo(IItem item, IEnumerable<MemberInfo> infos, Func<string, Config> selector) {
162      List<JsonItem> parameters = new List<JsonItem>();
163      foreach(var info in infos) {
164        Config config = selector(info.Name);
165        if (config != null) {
166          object o = GetValue(info, item);
167          parameters.AddRange(config.Extract(o, GetType(info)));
168        }
169      }
170      return parameters;
171    }
172
173    private JsonItem ConvertPrimitive(string name, object obj) =>
174      new JsonItem() {
175        Name = name,
176        Value = obj
177      };
178
179    private object GetValue(MemberInfo info, object obj) {
180      switch (info.MemberType) {
181        case MemberTypes.Field:
182          return (info as FieldInfo).GetValue(obj);
183        case MemberTypes.Property:
184          PropertyInfo pi = info as PropertyInfo;
185          return (pi != null && pi.CanRead) ? pi.GetValue(obj) : null;
186        default: return null;
187      }
188    }
189
190    private Type GetType(MemberInfo info) {
191      switch (info.MemberType) {
192        case MemberTypes.Field:
193          return (info as FieldInfo).FieldType;
194        case MemberTypes.Property:
195          return (info as PropertyInfo).PropertyType;
196        default: return null;
197      }
198    }
199  }
200}
Note: See TracBrowser for help on using the repository browser.