Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 3937 was 3937, checked in by epitzer, 14 years ago

Estimate or calculate StringBuffer sizes in advance, use iterator over string splits instead of arrays. (#1138)

File size: 5.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using HeuristicLab.Persistence.Interfaces;
24using HeuristicLab.Persistence.Core;
25using System.Collections.Generic;
26using System.Reflection;
27using System.Globalization;
28using System.Text;
29using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
30using HeuristicLab.Persistence.Auxiliary;
31
32namespace HeuristicLab.Persistence.Default.CompositeSerializers {
33
34  [StorableClass]
35  internal sealed class NumberEnumerable2StringSerializer : ICompositeSerializer {
36
37    public int Priority {
38      get { return 200; }
39    }
40
41    private static readonly Number2StringSerializer numberConverter =
42      new Number2StringSerializer();
43
44    private static readonly Dictionary<Type, Type> interfaceCache = new Dictionary<Type, Type>();
45
46    public Type GetGenericEnumerableInterface(Type type) {
47      if (interfaceCache.ContainsKey(type))
48        return interfaceCache[type];
49      foreach (Type iface in type.GetInterfaces()) {
50        if (iface.IsGenericType &&
51          iface.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
52          numberConverter.CanSerialize(iface.GetGenericArguments()[0])) {
53          interfaceCache.Add(type, iface);
54          return iface;
55        }
56      }
57      interfaceCache.Add(type, null);
58      return null;
59    }
60
61    public bool ImplementsGenericEnumerable(Type type) {
62      return GetGenericEnumerableInterface(type) != null;
63    }
64
65    public bool HasAddMethod(Type type) {
66      return
67        type.GetMethod("Add") != null &&
68        type.GetMethod("Add").GetParameters().Length == 1 &&
69        type.GetConstructor(
70          BindingFlags.Public |
71          BindingFlags.NonPublic |
72          BindingFlags.Instance,
73          null, Type.EmptyTypes, null) != null;
74    }
75
76    public bool CanSerialize(Type type) {
77      return
78        ReflectionTools.HasDefaultConstructor(type) &&
79        ImplementsGenericEnumerable(type) &&
80        HasAddMethod(type);
81    }
82
83    public string JustifyRejection(Type type) {
84      if (!ReflectionTools.HasDefaultConstructor(type))
85        return "no default constructor";
86      if (!ImplementsGenericEnumerable(type))
87        return "IEnumerable<> not implemented";
88      return "no Add method with one parameter";
89    }
90
91    public IEnumerable<Tag> CreateMetaInfo(object o) {
92      return new Tag[] { };
93    }
94
95    private static object[] emptyArgs = new object[0];
96    public IEnumerable<Tag> Decompose(object obj) {
97      Type type = obj.GetType();
98      Type enumerable = GetGenericEnumerableInterface(type);
99      InterfaceMapping iMap = obj.GetType().GetInterfaceMap(enumerable);
100      MethodInfo getEnumeratorMethod =
101        iMap.TargetMethods[
102        Array.IndexOf(
103          iMap.InterfaceMethods,
104          enumerable.GetMethod("GetEnumerator"))];
105      object genericEnumerator = getEnumeratorMethod.Invoke(obj, emptyArgs);
106      MethodInfo moveNextMethod = genericEnumerator.GetType().GetMethod("MoveNext");
107      PropertyInfo currentProperty = genericEnumerator.GetType().GetProperty("Current");
108      StringBuilder sb = new StringBuilder();
109      while ((bool)moveNextMethod.Invoke(genericEnumerator, emptyArgs))
110        sb.Append(
111          numberConverter.Format(
112            currentProperty.GetValue(genericEnumerator, null))).Append(';');
113      yield return new Tag("compact enumerable", sb.ToString());
114    }
115
116    public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) {
117      return Activator.CreateInstance(type, true);
118    }
119
120    public void Populate(object instance, IEnumerable<Tag> tags, Type type) {
121      Type enumerable = GetGenericEnumerableInterface(type);
122      Type elementType = enumerable.GetGenericArguments()[0];
123      MethodInfo addMethod = type.GetMethod("Add");
124      try {
125        var tagEnumerator = tags.GetEnumerator();
126        tagEnumerator.MoveNext();
127        string[] stringValues = ((string)tagEnumerator.Current.Value)
128          .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
129        foreach (var value in stringValues) {
130          addMethod.Invoke(instance, new[] { numberConverter.Parse(value, elementType) });
131        }
132      } catch (InvalidOperationException e) {
133        throw new PersistenceException("Insufficient element data to reconstruct number enumerable", e);
134      } catch (InvalidCastException e) {
135        throw new PersistenceException("Invalid element data during reconstruction of number enumerable", e);
136      }
137    }
138  }
139}
Note: See TracBrowser for help on using the repository browser.