1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using System.Linq;
|
---|
4 | using System.Text;
|
---|
5 | using System.Reflection;
|
---|
6 |
|
---|
7 | namespace HeuristicLab.Persistence.Default.CompositeSerializers.Storable {
|
---|
8 |
|
---|
9 | public enum HookType { BeforeSerialization, AfterDeserialization };
|
---|
10 |
|
---|
11 | [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
|
---|
12 | public sealed class StorableHookAttribute : Attribute {
|
---|
13 |
|
---|
14 | private sealed class HookDesignator {
|
---|
15 | public Type Type { get; set; }
|
---|
16 | public HookType HookType { get; set; }
|
---|
17 | public HookDesignator() { }
|
---|
18 | public HookDesignator(Type type, HookType hookType) {
|
---|
19 | Type = type;
|
---|
20 | HookType = HookType;
|
---|
21 | }
|
---|
22 | }
|
---|
23 |
|
---|
24 | private readonly HookType hookType;
|
---|
25 | public HookType HookType {
|
---|
26 | get { return hookType; }
|
---|
27 | }
|
---|
28 |
|
---|
29 | public StorableHookAttribute(HookType hookType) {
|
---|
30 | this.hookType = hookType;
|
---|
31 | }
|
---|
32 |
|
---|
33 | private static readonly BindingFlags instanceMembers =
|
---|
34 | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
|
---|
35 |
|
---|
36 | private static readonly object[] emptyArgs = new object[] { };
|
---|
37 |
|
---|
38 | private static Dictionary<HookDesignator, List<MethodInfo>> hookCache =
|
---|
39 | new Dictionary<HookDesignator, List<MethodInfo>>();
|
---|
40 |
|
---|
41 | public static void InvokeHook(HookType hookType, object obj) {
|
---|
42 | if (obj == null)
|
---|
43 | throw new ArgumentNullException("Cannot invoke hooks on null");
|
---|
44 | foreach (MethodInfo mi in GetHooks(hookType, obj.GetType())) {
|
---|
45 | mi.Invoke(obj, emptyArgs);
|
---|
46 | }
|
---|
47 | }
|
---|
48 |
|
---|
49 | private static IEnumerable<MethodInfo> GetHooks(HookType hookType, Type type) {
|
---|
50 | lock (hookCache) {
|
---|
51 | List<MethodInfo> hooks;
|
---|
52 | var designator = new HookDesignator(type, hookType);
|
---|
53 | hookCache.TryGetValue(designator, out hooks);
|
---|
54 | if (hooks != null)
|
---|
55 | return hooks;
|
---|
56 | hooks = new List<MethodInfo>(CollectHooks(hookType, type));
|
---|
57 | hookCache.Add(designator, hooks);
|
---|
58 | return hooks;
|
---|
59 | }
|
---|
60 | }
|
---|
61 |
|
---|
62 | private static IEnumerable<MethodInfo> CollectHooks(HookType hookType, Type type) {
|
---|
63 | foreach (MemberInfo memberInfo in type.GetMembers(instanceMembers)) {
|
---|
64 | foreach (StorableHookAttribute hook in memberInfo.GetCustomAttributes(typeof(StorableHookAttribute), false)) {
|
---|
65 | if (hook != null && hook.HookType == hookType) {
|
---|
66 | MethodInfo methodInfo = memberInfo as MethodInfo;
|
---|
67 | if (memberInfo.MemberType != MemberTypes.Method || memberInfo == null)
|
---|
68 | throw new ArgumentException("Storable hooks must be methods");
|
---|
69 | yield return methodInfo;
|
---|
70 | }
|
---|
71 | }
|
---|
72 | }
|
---|
73 | }
|
---|
74 |
|
---|
75 | }
|
---|
76 | } |
---|