View difference between Paste ID: ctLRd13B and pNRS3qQX
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
    }