Free cookie consent management tool by TermsFeed Policy Generator

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

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

split off test case, format empty variable names, include assembly names (#506)

File size: 9.8 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  public 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 class DataMemberAccessor {
213
214    public delegate object Getter();
215    public delegate void Setter(object value);
216
217    public readonly Getter Get;
218    public readonly Setter Set;
219    public readonly string Name;
220    public readonly Type Type;
221    public readonly object DefaultValue;
222
223    public DataMemberAccessor(
224        MemberInfo memberInfo,
225        StorableAttribute autoStorableAttribute,
226        object obj) {
227      if (memberInfo.MemberType == MemberTypes.Field) {
228        FieldInfo fieldInfo = (FieldInfo)memberInfo;
229        Get = () => fieldInfo.GetValue(obj);
230        Set = value => fieldInfo.SetValue(obj, value);
231        Type = fieldInfo.FieldType;
232      } else if (memberInfo.MemberType == MemberTypes.Property) {
233        PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
234        if (!propertyInfo.CanRead || !propertyInfo.CanWrite) {
235          throw new NotSupportedException(
236            "Storable properties must implement both a Get and a Set Accessor. ");
237        }
238        Get = () => propertyInfo.GetValue(obj, null);
239        Set = value => propertyInfo.SetValue(obj, value, null);
240        Type = propertyInfo.PropertyType;
241      } else {
242        throw new NotSupportedException(
243                "The Storable attribute can only be applied to fields and properties.");
244      }     
245      Name = autoStorableAttribute.Name ?? memberInfo.Name;     
246      DefaultValue = autoStorableAttribute.DefaultValue;                 
247    }
248
249    public DataMemberAccessor(
250        string name, Type type, object defaultValue,
251        Getter getter, Setter setter) {
252      Name = name;
253      Type = type;
254      DefaultValue = defaultValue;
255      Get = getter;
256      Set = setter;
257    }
258
259    public DataMemberAccessor(object o) {     
260      Name = null;
261      Type = o.GetType();
262      DefaultValue = null;
263      Get = () => o;
264      Set = null;
265    }       
266    public override string ToString() {
267      return String.Format("DataMember({0}, {1}, {2}, {3}, {4}",
268        Name,
269        Type == null ? "<null>" : Type.FullName,
270        DefaultValue ?? "<null>",
271        Get.Method,
272        Set.Method);
273    }
274  }
275
276}
Note: See TracBrowser for help on using the repository browser.