Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/NumberEnumerable2StringSerializer.cs @ 3004

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

Make StorableClass attribute compulsory for StorableSerializer to work, add named property StorableClassType to choose between Empty and MarkedOnly, later other options will be added. (#548)

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