SHOW:
|
|
- or go back to the newest paste.
1 | public abstract class EventHandle : IDisposable | |
2 | { | |
3 | ||
4 | public static EventHandle<TTarget, THandler> Create<TTarget, THandler>( | |
5 | TTarget target, | |
6 | THandler callback, | |
7 | Action<TTarget, THandler> add, | |
8 | Action<TTarget, THandler> remove) | |
9 | where TTarget : class | |
10 | where THandler : ICloneable, ISerializable | |
11 | { | |
12 | return new EventHandle<TTarget, THandler>(target, callback, add, remove); | |
13 | } | |
14 | ||
15 | public abstract object Target { get; } | |
16 | public abstract void Dispose(); | |
17 | ||
18 | } | |
19 | ||
20 | public class EventHandle<TTarget, THandler> : EventHandle | |
21 | where TTarget : class | |
22 | where THandler : ICloneable, ISerializable | |
23 | { | |
24 | ||
25 | #region Static | |
26 | ||
27 | static Func<Proxy, THandler> _createHandler; | |
28 | ||
29 | static EventHandle() | |
30 | { | |
31 | if (typeof(Delegate).IsAssignableFrom(typeof(THandler))) | |
32 | { | |
33 | var invokeMethod = typeof(THandler).GetMethod("Invoke"); | |
34 | var invokeMethodParamters = invokeMethod.GetParameters(); | |
35 | var callbackField = typeof(Proxy).GetField("Callback"); | |
36 | var disposedField = typeof(Proxy).GetField("Disposed"); | |
37 | ||
38 | var @parameters = new ParameterExpression[invokeMethodParamters.Length]; | |
39 | for (int i = 0; i < @parameters.Length; i++) | |
40 | { | |
41 | @parameters[i] = | |
42 | Expression.Parameter(invokeMethodParamters[i].ParameterType); | |
43 | } | |
44 | ||
45 | var @proxy = | |
46 | Expression.Parameter(typeof(Proxy)); | |
47 | ||
48 | var @callback = | |
49 | Expression.Variable(typeof(THandler)); | |
50 | ||
51 | var @getCallback = | |
52 | Expression.Assign( | |
53 | @callback, | |
54 | Expression.TypeAs( | |
55 | Expression.Property( | |
56 | Expression.Field( | |
57 | @proxy, | |
58 | callbackField), | |
59 | "Target"), | |
60 | typeof(THandler))); | |
61 | ||
62 | var @tryInvoke = | |
63 | Expression.IfThen( | |
64 | Expression.Not( | |
65 | Expression.Field( | |
66 | @proxy, | |
67 | "Disposed")), | |
68 | Expression.IfThenElse( | |
69 | Expression.NotEqual( | |
70 | @callback, | |
71 | Expression.Constant(null, typeof(THandler))), | |
72 | Expression.Invoke( | |
73 | @callback, | |
74 | @parameters), | |
75 | Expression.Call( | |
76 | @proxy, | |
77 | "Dispose", | |
78 | new Type[0]))); | |
79 | ||
80 | _createHandler = | |
81 | Expression.Lambda<Func<Proxy, THandler>>( | |
82 | Expression.Lambda<THandler>( | |
83 | Expression.Block( | |
84 | new ParameterExpression[] | |
85 | { | |
86 | @callback, | |
87 | }, | |
88 | new Expression[] | |
89 | { | |
90 | @getCallback, | |
91 | @tryInvoke, | |
92 | }), | |
93 | @parameters), | |
94 | @proxy) | |
95 | .Compile(); | |
96 | } | |
97 | } | |
98 | ||
99 | #endregion | |
100 | ||
101 | private Proxy _proxy; | |
102 | private THandler _callback; | |
103 | ||
104 | public EventHandle(TTarget target, THandler callback, Action<TTarget, THandler> add, Action<TTarget, THandler> remove) | |
105 | { | |
106 | if (!typeof(Delegate).IsAssignableFrom(typeof(THandler))) throw new ArgumentException("delegate type expected", "T"); | |
107 | if (target == null) throw new ArgumentNullException("add"); | |
108 | if (callback == null) throw new ArgumentNullException("add"); | |
109 | if (add == null) throw new ArgumentNullException("add"); | |
110 | if (remove == null) throw new ArgumentNullException("remove"); | |
111 | ||
112 | _proxy = new Proxy(target, callback, add, remove); | |
113 | _callback = callback; | |
114 | } | |
115 | ||
116 | ~EventHandle() | |
117 | { | |
118 | Dispose(); | |
119 | } | |
120 | ||
121 | public override object Target | |
122 | { | |
123 | get { return _proxy.Target; } | |
124 | } | |
125 | ||
126 | public override void Dispose() | |
127 | { | |
128 | if (_proxy != null) | |
129 | { | |
130 | _proxy.Dispose(); | |
131 | _proxy = null; | |
132 | } | |
133 | } | |
134 | ||
135 | private class Proxy : IDisposable | |
136 | { | |
137 | ||
138 | public bool Disposed; | |
139 | public TTarget Target; | |
140 | public WeakReference Callback; | |
141 | public Action<TTarget, THandler> Add; | |
142 | public Action<TTarget, THandler> Remove; | |
143 | public THandler Handler; | |
144 | ||
145 | public Proxy(TTarget target, THandler callback, Action<TTarget, THandler> add, Action<TTarget, THandler> remove) | |
146 | { | |
147 | Disposed = false; | |
148 | Target = target; | |
149 | Callback = new WeakReference(callback); | |
150 | Add = add; | |
151 | Remove = remove; | |
152 | Handler = _createHandler(this); | |
153 | ||
154 | Add(Target, Handler); | |
155 | } | |
156 | ||
157 | public void Dispose() | |
158 | { | |
159 | if (!Disposed) | |
160 | { | |
161 | - | if (Target != null) |
161 | + | Remove(Target, Handler); |
162 | - | { |
162 | + | |
163 | - | Remove(Target, Handler); |
163 | + | |
164 | - | } |
164 | + | |
165 | ||
166 | } | |
167 | ||
168 | } | |
169 | ||
170 | public static class EventHandleExtensions | |
171 | { | |
172 | ||
173 | public static EventHandle SubscribeCollectionChanged(this INotifyCollectionChanged target, NotifyCollectionChangedEventHandler callback) | |
174 | { | |
175 | return EventHandle.Create( | |
176 | target, | |
177 | callback, | |
178 | (t, h) => t.CollectionChanged += h, | |
179 | (t, h) => t.CollectionChanged -= h); | |
180 | } | |
181 | ||
182 | public static EventHandle SubscribePropertyChanged(this INotifyPropertyChanged target, PropertyChangedEventHandler callback) | |
183 | { | |
184 | return EventHandle.Create( | |
185 | target, | |
186 | callback, | |
187 | (t, h) => t.PropertyChanged += h, | |
188 | (t, h) => t.PropertyChanged -= h); | |
189 | } | |
190 | ||
191 | public static EventHandle SubscribePropertyChanged(this INotifyPropertyChanged target, PropertyChangedEventHandler callback, string propertyName) | |
192 | { | |
193 | return target.SubscribePropertyChanged((s, e) => | |
194 | { | |
195 | if (string.IsNullOrEmpty(e.PropertyName) || e.PropertyName == propertyName) | |
196 | { | |
197 | callback(s, e); | |
198 | } | |
199 | }); | |
200 | } | |
201 | ||
202 | } |