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

Last change on this file since 1332 was 1332, checked in by epitzer, 12 years ago

Enable object instantiation using non-public default constructors. (#506)

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