Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Default/Decomposers/NumberEnumerable2StringDecomposer.cs @ 1644

Last change on this file since 1644 was 1644, checked in by epitzer, 15 years ago

support for default disabled decomposers, re-activate number2string decomposer with negative priority. (#548)

File size: 4.0 KB
Line 
1using System;
2using HeuristicLab.Persistence.Interfaces;
3using HeuristicLab.Persistence.Core;
4using System.Collections.Generic;
5using System.Reflection;
6using System.Globalization;
7using System.Text;
8using HeuristicLab.Persistence.Default.Decomposers.Storable;
9
10namespace HeuristicLab.Persistence.Default.Decomposers {
11
12  [EmptyStorableClass]
13  public class NumberEnumerable2StringDecomposer : IDecomposer {
14
15    public int Priority {
16      get { return 200; }
17    }
18
19    private static readonly Number2StringDecomposer numberConverter =
20      new Number2StringDecomposer();
21
22    private static readonly Dictionary<Type, Type> interfaceCache = new Dictionary<Type, Type>();
23
24    public Type GetGenericEnumerableInterface(Type type) {
25      if (interfaceCache.ContainsKey(type))
26        return interfaceCache[type];
27      foreach (Type iface in type.GetInterfaces()) {
28        if (iface.IsGenericType &&
29          iface.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
30          numberConverter.CanDecompose(iface.GetGenericArguments()[0])) {
31          interfaceCache.Add(type, iface);
32          return iface;
33        }
34      }
35      interfaceCache.Add(type, null);
36      return null;
37    }
38
39    public bool ImplementsGenericEnumerable(Type type) {
40      return GetGenericEnumerableInterface(type) != null;
41    }
42
43    public bool HasAddMethod(Type type) {
44      return
45        type.GetMethod("Add") != null &&
46        type.GetMethod("Add").GetParameters().Length == 1 &&
47        type.GetConstructor(
48          BindingFlags.Public |
49          BindingFlags.NonPublic |
50          BindingFlags.Instance,
51          null, Type.EmptyTypes, null) != null;
52    }
53
54    public bool CanDecompose(Type type) {
55      return
56        ImplementsGenericEnumerable(type) &&
57        HasAddMethod(type);
58    }
59
60    public IEnumerable<Tag> CreateMetaInfo(object o) {
61      return new Tag[] { };
62    }
63
64    public IEnumerable<Tag> Decompose(object obj) {
65      Type type = obj.GetType();
66      Type enumerable = GetGenericEnumerableInterface(type);
67      InterfaceMapping iMap = obj.GetType().GetInterfaceMap(enumerable);
68      MethodInfo getEnumeratorMethod =
69        iMap.TargetMethods[
70        Array.IndexOf(
71          iMap.InterfaceMethods,
72          enumerable.GetMethod("GetEnumerator"))];
73      object[] empty = new object[] { };
74      object genericEnumerator = getEnumeratorMethod.Invoke(obj, empty);
75      MethodInfo moveNextMethod = genericEnumerator.GetType().GetMethod("MoveNext");
76      PropertyInfo currentProperty = genericEnumerator.GetType().GetProperty("Current");
77      StringBuilder sb = new StringBuilder();
78      while ((bool)moveNextMethod.Invoke(genericEnumerator, empty))
79        sb.Append(
80          numberConverter.Format(
81            currentProperty.GetValue(genericEnumerator, null))).Append(';');
82      yield return new Tag("compact enumerable", sb.ToString());
83    }
84
85    public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) {
86      return Activator.CreateInstance(type, true);
87    }
88
89    public void Populate(object instance, IEnumerable<Tag> tags, Type type) {
90      Type enumerable = GetGenericEnumerableInterface(type);
91      Type elementType = enumerable.GetGenericArguments()[0];
92      MethodInfo addMethod = type.GetMethod("Add");
93      try {
94        var tagEnumerator = tags.GetEnumerator();
95        tagEnumerator.MoveNext();
96        string[] stringValues = ((string)tagEnumerator.Current.Value)
97          .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
98        foreach (var value in stringValues) {
99          addMethod.Invoke(instance, new[] { numberConverter.Parse(value, elementType) });
100        }
101      } catch (InvalidOperationException e) {
102        throw new PersistenceException("Insufficient element data to reconstruct number enumerable", e);
103      } catch (InvalidCastException e) {
104        throw new PersistenceException("Invalid element data during reconstruction of number enumerable", e);
105      }
106    }
107  }
108}
Note: See TracBrowser for help on using the repository browser.