forked from SharpMap/SharpMap
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathEventListener.cs
113 lines (87 loc) · 3.98 KB
/
EventListener.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace UnitTests
{
internal class EventListener
{
#region static helpers fields
private static readonly ConstructorInfo _dictionaryCto =
typeof(Dictionary<string, object>).GetConstructor(Type.EmptyTypes);
private static readonly MethodInfo _dictionarySetItemMethod =
typeof(Dictionary<string, object>).GetProperty("Item").GetSetMethod();
private static readonly MethodInfo _listAddMethod = typeof(ObservableCollection<Dictionary<string, object>>).GetMethod("Add");
#endregion
private readonly ObservableCollection<Dictionary<string, object>> _savedArgs = new ObservableCollection<Dictionary<string, object>>();
private List<dynamic> _dynamicSavedArgs;
public EventListener(object raiser, string eventName)
{
EventInfo eventInfo = raiser.GetType().GetEvent(eventName);
var handler = CreateCompatibleListener(eventInfo);
eventInfo.AddEventHandler(raiser, handler);
}
private Delegate CreateCompatibleListener(EventInfo eventInfo)
{
string methodName = eventInfo.Name + "_handler_";
var delegateType = eventInfo.EventHandlerType;
var invokeMethod = delegateType.GetMethod("Invoke");
if (invokeMethod.ReturnType != typeof(void))
throw new NotSupportedException();
var delegateParameters = invokeMethod.GetParameters();
var args = new List<Type> {typeof (EventListener)};
args.AddRange(delegateParameters.Select(p=>p.ParameterType));
var dm = new DynamicMethod(methodName,
typeof (void),
args.ToArray(),
typeof(EventListener));
var generator = dm.GetILGenerator(256);
generator.DeclareLocal(typeof (Dictionary<string, object>));
generator.Emit(OpCodes.Newobj, _dictionaryCto);
generator.Emit(OpCodes.Stloc_0);
var savedArgsField = GetType().GetField("_savedArgs", BindingFlags.Instance | BindingFlags.NonPublic);
Debug.Assert(savedArgsField != null);
// add the arguments received to the dictionary
for (var idx = 0; idx < delegateParameters.Length; idx++)
{
var parameter = delegateParameters[idx];
dm.DefineParameter(idx + 2, ParameterAttributes.In, parameter.Name);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldstr, parameter.Name);
generator.Emit(OpCodes.Ldarg, idx + 1);
if (parameter.ParameterType.IsValueType)
{
generator.Emit(OpCodes.Box, parameter.ParameterType);
}
generator.Emit(OpCodes.Callvirt, _dictionarySetItemMethod);
}
// add the dictionary to the list
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, savedArgsField);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Callvirt, _listAddMethod);
generator.Emit(OpCodes.Ret);
return dm.CreateDelegate(delegateType, this);
}
public ObservableCollection<Dictionary<string, object>> SavedArgs
{
get
{
return _savedArgs;
}
}
public IList<dynamic> DynamicSavedArgs
{
get
{
return _dynamicSavedArgs ??
(_dynamicSavedArgs = _savedArgs.Select(dict => (dynamic) dict.ToExpando()).ToList());
}
}
}
}