Free cookie consent management tool by TermsFeed Policy Generator

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

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

replace Functional with Linq

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