C#防止事件重复注册

【方法】

  • 在注册前先检查该订阅者是否已经注册过
  • 在注册前先移除然后再注册

【代码实现】

using System;
using System.Collections.Generic;
using System.Reflection;



namespace 笔试
{
    class Program
    {
        static void Main(string[] args)
        {
            MyDelegate myDelegate=new MyDelegate();
            Test test=new Test();

            Console.WriteLine("每次注册前先检查是否重复:");           
            if (TryAdd(myDelegate.valueChange,"Fun1"))
               myDelegate.valueChange += test.Fun1;
            if (TryAdd(myDelegate.valueChange, "Fun1"))
                myDelegate.valueChange += test.Fun1;
            if (TryAdd(myDelegate.valueChange, "Fun2"))
                myDelegate.valueChange += test.Fun2;
            myDelegate.CurNum = 10;
            myDelegate.Mul(5);

            Console.WriteLine("每次注册前先移除:");
            myDelegate.numAction += test.Fun1;
            myDelegate.numAction += test.Fun1;
            myDelegate.numAction += test.Fun2;
            myDelegate.Add(6);
            
            Console.ReadKey();
        }

        public static bool TryAdd(MyDelegate.numDelegate tempDelegate,string methodName)
        {
            if (tempDelegate == null)//委托为空直接返回
                return true;
            Delegate[] delegates = tempDelegate.GetInvocationList();//获取委托列表
            for (int i = 0; i < delegates.Length; i++)
            {
                if (delegates[i].GetMethodInfo().Name.Equals(methodName))//遍历委托列表,通过反射获取注册的方法名,判断与待注册的方法名是否相等
                {
                    return false;
                }
            }
            return true;
        }
    }


    public class MyDelegate
    {
        
        public delegate void numDelegate(int x);

        public numDelegate valueChange;

        private int _CurNum;

        public int CurNum
        {
            get { return _CurNum; }
            set
            {
                _CurNum = value;
                numDelegate tempDelegate = valueChange;//将委托引用复制到局部变量中,确保在检查空值和通知之间,所有订阅者被另一个线程移除时不会引发空引用异常
                if(tempDelegate!= null)//调用委托前检查是否为空
                   tempDelegate(value);//通知所有订阅者
            }
        }
        public void Mul(int x)
        {
            _CurNum *= x;
            numDelegate tempDelegate = valueChange;
            tempDelegate?.Invoke(_CurNum);//判空+通知的简写方式
        }


        //自定义实现add和remove块,类似属性
        private Action _numAction;
        public event Action numAction//自定义事件的add和remove块,类似自定义get和set
        {
            add
            {
                _numAction -= value;//每次添加前,先删除订阅者,然后添加订阅者就防止重复注册事件
                _numAction += value;
            }
            remove
            {
                _numAction -= value;                
            }
        }

        public void Add(int x)
        {
            _CurNum += x;
            _numAction(_CurNum);//事件不用检查是否为空
            
        }
    }

    public class Test
    {
        public void Fun1(int val)
        {
            Console.WriteLine("值增加2倍" + val*2);
        }

        public void Fun2(int val)
        {
            Console.WriteLine("值减小2倍" + val/2);
        }
    }
}

【代码输出】

C#防止事件重复注册_第1张图片

 

你可能感兴趣的:(C#,重复注册,C#)