zoukankan      html  css  js  c++  java
  • C# WeakEvent

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Reflection.Emit;
    using System.Runtime.CompilerServices;
    using System.Text;
    
    namespace Rocky
    {
        internal delegate bool Forwarder(WeakReference weakRef, object sender, EventArgs e);
    
        /// <summary>
        /// The forwarder-generating code is in a separate class because it does not depend on type T.
        /// </summary>
        internal static class WeakEventForwarderProvider
        {
            private static MethodInfo getTarget;
            private static Type[] forwarderParameters;
            private static Hashtable forwarders;
    
            static WeakEventForwarderProvider()
            {
                getTarget = typeof(WeakReference).GetMethod("get_Target");
                forwarderParameters = new Type[] { typeof(WeakReference), typeof(object), typeof(EventArgs) };
                forwarders = Hashtable.Synchronized(new Hashtable());
            }
    
            internal static Forwarder GetForwarder(MethodInfo method)
            {
                var fd = (Forwarder)forwarders[method];
                if (fd != null)
                {
                    return fd;
                }
                if (method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0)
                {
                    throw new ArgumentException("Cannot create weak event to anonymous method with closure.");
                }
    
                ParameterInfo[] parameters = method.GetParameters();
                DynamicMethod dm = new DynamicMethod("WeakEvent", typeof(bool), forwarderParameters, method.DeclaringType);
                ILGenerator il = dm.GetILGenerator();
                if (!method.IsStatic)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.EmitCall(OpCodes.Callvirt, getTarget, null);
                    il.Emit(OpCodes.Dup);
                    Label label = il.DefineLabel();
                    il.Emit(OpCodes.Brtrue, label);
                    il.Emit(OpCodes.Pop);
                    il.Emit(OpCodes.Ldc_I4_1);
                    il.Emit(OpCodes.Ret);
                    il.MarkLabel(label);
                    // The castclass here is required for the generated code to be verifiable.
                    // We can leave it out because we know this cast will always succeed
                    // (the instance/method pair was taken from a delegate).
                    // Unverifiable code is fine because private reflection is only allowed under FullTrust
                    // anyways.
                    //il.Emit(OpCodes.Castclass, method.DeclaringType);
                }
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldarg_2);
                // This castclass here is required to prevent creating a hole in the .NET type system.
                // See Program.TypeSafetyProblem in the 'SmartWeakEventBenchmark' to see the effect when
                // this cast is not used.
                // You can remove this cast if you trust add FastSmartWeakEvent.Raise callers to do
                // the right thing, but the small performance increase (about 5%) usually isn't worth the risk.
                il.Emit(OpCodes.Castclass, parameters[1].ParameterType);
    
                il.EmitCall(OpCodes.Call, method, null);
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Ret);
                forwarders[method] = fd = (Forwarder)dm.CreateDelegate(typeof(Forwarder));
                return fd;
            }
    
            internal static void OverForwarder(MethodInfo method)
            {
                forwarders.Remove(method);
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections.Specialized;
    using System.Reflection;
    using System.Reflection.Emit;
    
    namespace Rocky
    {
        public sealed class WeakEvent<T> where T : class
        {
            #region NestedTypes
            private struct EventEntry
            {
                public readonly Forwarder Forwarder;
                public readonly MethodInfo TargetMethod;
                public readonly WeakReference TargetReference;
    
                public EventEntry(Forwarder forwarder, MethodInfo targetMethod, WeakReference targetReference)
                {
                    this.Forwarder = forwarder;
                    this.TargetMethod = targetMethod;
                    this.TargetReference = targetReference;
                }
            }
            #endregion
    
            #region Static
            static WeakEvent()
            {
                Type type = typeof(T);
                if (!type.IsSubclassOf(typeof(Delegate)))
                {
                    throw new ArgumentException("T must be a delegate type");
                }
                MethodInfo invoke = type.GetMethod("Invoke");
                if (invoke == null || invoke.GetParameters().Length != 2)
                {
                    throw new ArgumentException("T must be a delegate type taking 2 parameters");
                }
                ParameterInfo senderParameter = invoke.GetParameters()[0];
                if (senderParameter.ParameterType != typeof(object))
                {
                    throw new ArgumentException("The first delegate parameter must be of type 'object'");
                }
                ParameterInfo argsParameter = invoke.GetParameters()[1];
                if (!(typeof(EventArgs).IsAssignableFrom(argsParameter.ParameterType)))
                {
                    throw new ArgumentException("The second delegate parameter must be derived from type 'EventArgs'");
                }
                if (invoke.ReturnType != typeof(void))
                {
                    throw new ArgumentException("The delegate return type must be void.");
                }
            }
            #endregion
    
            private List<EventEntry> eventEntries;
    
            private object SyncRoot
            {
                get { return eventEntries; }
            }
    
            public WeakEvent()
            {
                eventEntries = new List<EventEntry>();
            }
    
            private void RemoveEntry(int index, MethodInfo method)
            {
                lock (SyncRoot)
                {
                    eventEntries.RemoveAt(index);
                }
                WeakEventForwarderProvider.OverForwarder(method);
            }
    
            private void RemoveDeadEntries()
            {
                lock (SyncRoot)
                {
                    eventEntries.RemoveAll(entry =>
                    {
                        if (entry.TargetReference != null && !entry.TargetReference.IsAlive)
                        {
                            WeakEventForwarderProvider.OverForwarder(entry.TargetMethod);
                            return true;
                        }
                        return false;
                    });
                }
            }
    
            public void Add(T e)
            {
                if (e == null)
                {
                    return;
                }
    
                Delegate d = (Delegate)(object)e;
                if (eventEntries.Count == eventEntries.Capacity)
                {
                    RemoveDeadEntries();
                }
                MethodInfo targetMethod = d.Method;
                object targetInstance = d.Target;
                WeakReference target = targetInstance != null ? new WeakReference(targetInstance) : null;
                lock (SyncRoot)
                {
                    eventEntries.Add(new EventEntry(WeakEventForwarderProvider.GetForwarder(targetMethod), targetMethod, target));
                }
            }
    
            public void Remove(T e)
            {
                if (e == null)
                {
                    return;
                }
    
                Delegate d = (Delegate)(object)e;
                object targetInstance = d.Target;
                MethodInfo targetMethod = d.Method;
                lock (SyncRoot)
                {
                    for (int i = eventEntries.Count - 1; i >= 0; i--)
                    {
                        EventEntry entry = eventEntries[i];
                        if (entry.TargetReference != null)
                        {
                            object target = entry.TargetReference.Target;
                            if (target == null)
                            {
                                RemoveEntry(i, entry.TargetMethod);
                            }
                            else if (target == targetInstance && entry.TargetMethod == targetMethod)
                            {
                                RemoveEntry(i, entry.TargetMethod);
                                break;
                            }
                        }
                        else
                        {
                            if (targetInstance == null && entry.TargetMethod == targetMethod)
                            {
                                RemoveEntry(i, entry.TargetMethod);
                                break;
                            }
                        }
                    }
                }
            }
    
            public bool Raise()
            {
                return Raise(this, EventArgs.Empty);
            }
            public bool Raise(object sender, EventArgs e)
            {
                bool needClear = false;
                foreach (EventEntry entry in eventEntries)
                {
                    needClear |= entry.Forwarder(entry.TargetReference, sender, e);
                }
                if (needClear)
                {
                    RemoveDeadEntries();
                }
                return eventEntries.Count > 0;
            }
        }
    }
  • 相关阅读:
    android隐藏底部虚拟键Navigation Bar实现全屏
    TextView.setTextColor颜色值的理解
    GridLayout自定义数字键盘(两个EditText)
    EditText的一些属性及用法
    比较两个Long对象值
    vue全家桶(vue-cli,vue-router,vue-resource,vuex)-1
    vue-vuex状态管理-1
    vue-router进阶-3-过渡动效
    vue-router进阶-2-路由原信息
    vue-router进阶-1-导航守卫
  • 原文地址:https://www.cnblogs.com/Googler/p/2988603.html
Copyright © 2011-2022 走看看