Guest User

EventHandle

a guest
Jul 4th, 2012
346
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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.                     Remove(Target, Handler);
  162.                     Disposed = true;
  163.                 }
  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.     }
RAW Paste Data