Guest User

EventHandle

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