Free cookie consent management tool by TermsFeed Policy Generator

source: branches/New Persistence Exploration/Persistence/Persistence/StorableAttribute.cs @ 1357

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

Pluginification and major refactoring. (#506)

File size: 9.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Reflection;
4using System.Linq;
5using HeuristicLab.Persistence.Interfaces;
6
7namespace HeuristicLab.Persistence {
8
9  [AttributeUsage(
10    AttributeTargets.Field | AttributeTargets.Property,
11    AllowMultiple=false,
12    Inherited=false)]
13  public class StorableAttribute : Attribute {
14
15    public string Name { get; set; }
16    public object DefaultValue { get; set; }
17
18    private const BindingFlags instanceMembers =
19      BindingFlags.Instance |
20      BindingFlags.Public |
21      BindingFlags.NonPublic;
22   
23    public static IEnumerable<KeyValuePair<StorableAttribute, MemberInfo>> GetStorableMembers(Type type) {
24      return GetStorableMembers(type, true);     
25    }
26
27    public static IEnumerable<KeyValuePair<StorableAttribute, MemberInfo>>
28        GetStorableMembers(Type type, bool inherited) {
29      if (type.BaseType != null)
30        foreach ( var pair in GetStorableMembers(type.BaseType) )
31          yield return pair;
32      foreach (MemberInfo memberInfo in type.GetMembers(instanceMembers)) {
33        foreach (object attribute in memberInfo.GetCustomAttributes(false)) {         
34          StorableAttribute storableAttribute =
35            attribute as StorableAttribute;
36          if (storableAttribute != null) {
37            yield return new KeyValuePair<StorableAttribute, MemberInfo>(storableAttribute, memberInfo);           
38          }
39        }
40      }     
41    }
42
43    public static Dictionary<string, DataMemberAccessor> GetAutostorableAccessors(object obj) {
44      Dictionary<string, DataMemberAccessor> storableAccessors =
45        new Dictionary<string, DataMemberAccessor>();
46      foreach (KeyValuePair<StorableAttribute, MemberInfo> pair in GetStorableMembers(obj.GetType())) {
47        storableAccessors.Add(pair.Value.Name,
48          new DataMemberAccessor(pair.Value, pair.Key, obj));
49      }           
50      return storableAccessors;
51    }   
52  }
53
54  public class CloningFactory {
55
56    private static readonly CloningFactory instance = new CloningFactory();
57
58    public static T DefaultClone<T>(T obj) {
59      return instance.Clone(obj);
60    }
61
62    private readonly List<IDecomposer> compoundSerializers;
63
64    public CloningFactory(IEnumerable<IDecomposer> compoundSerializers) {
65      this.compoundSerializers = new List<IDecomposer>(compoundSerializers);
66    }
67
68    public CloningFactory() :
69      this(InterfaceInstantiatior.InstantiateAll<IDecomposer>()) { }
70
71    delegate object CloneMethod(object obj, Dictionary<object, object> twins);
72
73    readonly Dictionary<Type, CloneMethod> cloneMethods = new Dictionary<Type, CloneMethod>();
74
75    public T Clone<T>(T obj) {
76      Dictionary<object, object> twins = new Dictionary<object, object>();
77      return Clone(obj, twins);
78    }
79
80    public T Clone<T>(T obj, Dictionary<object, object> twins) {
81      ValueType t = obj as ValueType;
82      if (t != null)
83        return obj;
84
85      // ReSharper disable CompareNonConstrainedGenericWithNull
86      if (obj == null)
87      // ReSharper restore CompareNonConstrainedGenericWithNull
88        return default(T);
89
90      if (twins.ContainsKey(obj))
91        return (T)twins[obj];
92
93      ICloneable c = obj as ICloneable;
94      if (c != null) {
95        T newClone = (T)c.Clone();
96        twins[obj] = newClone;
97        return newClone;
98      }
99
100      Type type = obj.GetType();
101      if (!cloneMethods.ContainsKey(type))
102        cloneMethods[type] = CreateCloneMethod(type);
103      return (T)cloneMethods[type](obj, twins);
104    }
105
106    private CloneMethod CreateCloneMethod(Type type) {
107      if (type.GetConstructor(new[] { type }) != null)
108        return CopyConstructorCloneMethod.Create(type);
109      foreach (IDecomposer serializer in compoundSerializers)
110        if (serializer.CanSerialize(type))
111          return CompoundSerializerCloneMethod.Create(serializer, type, this);
112      return StorableAccessorCloneMethod.Create(type, this);     
113    }
114
115    class CopyConstructorCloneMethod {
116      public static CloneMethod Create(Type type) {
117        return new CopyConstructorCloneMethod(type).method;
118      }
119      private readonly ConstructorInfo constructorInfo;
120      public CopyConstructorCloneMethod(Type type) {
121        constructorInfo = type.GetConstructor(new[] { type });
122      }
123      object method(object obj, Dictionary<object, object> twins) {
124        object newInstance = constructorInfo.Invoke(new[] { obj });
125        twins.Add(obj, newInstance);
126        return newInstance;
127      }
128    }
129
130    class CompoundSerializerCloneMethod {
131      public static CloneMethod Create(IDecomposer serializer,
132          Type type, CloningFactory factory) {
133        return new CompoundSerializerCloneMethod(serializer, type, factory).method;
134      }
135      private readonly IDecomposer serializer;
136      private readonly Type type;
137      private readonly CloningFactory factory;
138      public CompoundSerializerCloneMethod(IDecomposer serializer,
139          Type type, CloningFactory factory) {
140        this.serializer = serializer;
141        this.type = type;
142        this.factory = factory;
143      }
144      object method(object obj, Dictionary<object, object> twins) {
145        return serializer.DeSerialize(
146          serializer.Serialize(obj)
147          .OfType<object>()
148          .Select(o => factory.Clone(o, twins)),
149          type);         
150      }
151    }
152
153    class StorableAccessorCloneMethod {
154
155      delegate object GetterMethod(object target);
156      delegate void SetterMethod(object target, object value);
157
158      struct FieldAccessor {     
159        public readonly GetterMethod Getter;
160        public readonly SetterMethod Setter;
161        public FieldAccessor(GetterMethod getter, SetterMethod setter) {
162          Getter = getter;
163          Setter = setter;
164        }
165      }
166
167      private const BindingFlags INSTANCE_MEMBERS =
168        BindingFlags.Instance |
169        BindingFlags.Public |
170        BindingFlags.NonPublic;
171
172      public static CloneMethod Create(Type type, CloningFactory factory) {
173        return new StorableAccessorCloneMethod(type, factory).method;
174      }
175
176      private readonly List<FieldAccessor> fieldAccessors;
177      private readonly CloningFactory factory;
178         
179      public StorableAccessorCloneMethod(Type type, CloningFactory factory) {
180        this.factory = factory;
181        fieldAccessors = new List<FieldAccessor>();
182        foreach (MemberInfo memberInfo in type.GetMembers(INSTANCE_MEMBERS)) {
183          foreach (object attribute in memberInfo.GetCustomAttributes(false)) {
184            StorableAttribute autoStorableAttribute =
185              attribute as StorableAttribute;
186            if (autoStorableAttribute != null) {
187              if (memberInfo.MemberType == MemberTypes.Field) {
188                FieldInfo fi = (FieldInfo)memberInfo;
189                fieldAccessors.Add(new FieldAccessor(
190                  fi.GetValue,
191                  fi.SetValue));
192              } else if (memberInfo.MemberType == MemberTypes.Property) {
193                PropertyInfo pi = (PropertyInfo)memberInfo;
194                fieldAccessors.Add(new FieldAccessor(
195                  target => pi.GetValue(target, null),
196                  (target, value) => pi.SetValue(target, value, null)));
197              }
198            }
199          }
200        }
201      }
202      object method(object obj, Dictionary<object, object> twins) {
203        object newInstance = Activator.CreateInstance(obj.GetType(), true);
204        twins.Add(obj, newInstance);
205        foreach (FieldAccessor fa in fieldAccessors) {
206          fa.Setter(newInstance, factory.Clone(fa.Getter(obj), twins));
207        }
208        return newInstance;
209      }
210    }
211  } 
212   
213  public class DataMemberAccessor {
214
215    public delegate object Getter();
216    public delegate void Setter(object value);
217
218    public readonly Getter Get;
219    public readonly Setter Set;
220    public readonly string Name;
221    public readonly Type Type;
222    public readonly object DefaultValue;
223
224    public DataMemberAccessor(
225        MemberInfo memberInfo,
226        StorableAttribute autoStorableAttribute,
227        object obj) {
228      if (memberInfo.MemberType == MemberTypes.Field) {
229        FieldInfo fieldInfo = (FieldInfo)memberInfo;
230        Get = () => fieldInfo.GetValue(obj);
231        Set = value => fieldInfo.SetValue(obj, value);
232        Type = fieldInfo.FieldType;
233      } else if (memberInfo.MemberType == MemberTypes.Property) {
234        PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
235        if (!propertyInfo.CanRead || !propertyInfo.CanWrite) {
236          throw new NotSupportedException(
237            "Storable properties must implement both a Get and a Set Accessor. ");
238        }
239        Get = () => propertyInfo.GetValue(obj, null);
240        Set = value => propertyInfo.SetValue(obj, value, null);
241        Type = propertyInfo.PropertyType;
242      } else {
243        throw new NotSupportedException(
244                "The Storable attribute can only be applied to fields and properties.");
245      }     
246      Name = autoStorableAttribute.Name ?? memberInfo.Name;     
247      DefaultValue = autoStorableAttribute.DefaultValue;                 
248    }
249
250    public DataMemberAccessor(
251        string name, Type type, object defaultValue,
252        Getter getter, Setter setter) {
253      Name = name;
254      Type = type;
255      DefaultValue = defaultValue;
256      Get = getter;
257      Set = setter;
258    }
259
260    public DataMemberAccessor(object o) {     
261      Name = null;
262      Type = o.GetType();
263      DefaultValue = null;
264      Get = () => o;
265      Set = null;
266    }       
267    public override string ToString() {
268      return String.Format("DataMember({0}, {1}, {2}, {3}, {4}",
269        Name,
270        Type == null ? "<null>" : Type.FullName,
271        DefaultValue ?? "<null>",
272        Get.Method,
273        Set.Method);
274    }
275  }
276
277}
Note: See TracBrowser for help on using the repository browser.