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 | } |