前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GeneralUpdate解决设计中异常传递问题

GeneralUpdate解决设计中异常传递问题

作者头像
JusterZhu
发布2023-08-10 11:31:48
1100
发布2023-08-10 11:31:48
举报
文章被收录于专栏:JusterZhuJusterZhu

一、概要

大家好我是juster,GeneralUpdate(一款应用程序自动升级组件)作者。在设计组件的时候也会遇到不少问题,经常会在半夜想到一个解决办法爬起来将这个办法或者是设计记录下来或者直接实现。这里将很久之前设计思路写出来向大家讨教、分享,在设计和实现的过程遇到的问题以及是如何解决的。

项目地址
  • https://github.com/JusterZhu/GeneralUpdate
  • https://gitee.com/Juster-zhu/GeneralUpdate

二、详细内容

下面这张图是用来描述在日常编码中我们编写代码的场景,像极了一颗“洋葱”。当异常逐层向外层传递时会受到一些影响。

  • 1.当一些类或者对象,被逐层调用导致调用层数比较深时。会导致异常抛出的信息不直观或者异常嵌信息套异常信息等情况。
  • 2.抛出的异常直接被try块或者其他机制给“吃”掉导致异常没有办法正常的向外层传递,最终导致收集不到更详细的异常导致我们排查问题困难日志信息记录确实的情况。

这个时候可能会想到,不断向外层传递异常信息的时候会有这些问题。如果集中将异常管理起来,点对点抛到最外层不就可以解决问题了吗?

确实,这样做简单明了但是光有解决思路不能落实成解决方案那么也只是产生了新的问题罢了。

那么我们简单分析一下设计的解决方案要满足什么样的条件:
  • 点对点传递异常,不会因为各种其他因素影响。
  • 能集中管理。
  • 能支持各种类型的消息抛出和接收,方便扩展。
  • 线程安全的。
  • 简单易用,方便管理。
  • 不管有多少地方需要知道异常都能点对点接收。

软件工程中流传着一句话,大部分软件问题通过增加一层就能解决,如果一层解决不了那就两层。

于是有了以下代码:

代码语言:javascript
复制
    /// <summary>
    /// Manage all events in the component.
    /// </summary>
    public class EventManager : IEventManager, IDisposable
    {
        // Use interop to call the method necessary
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private static extern Boolean CloseHandle(IntPtr handle);

        private static readonly object _lockObj = new object();
        private static EventManager _instance;
        private Dictionary<Type, Delegate> _dicDelegates = new Dictionary<Type, Delegate>();

        // Track whether Dispose has been called.
        private bool disposed = false;

        // Pointer to an external unmanaged resource.
        private IntPtr handle;

        // Other managed resource this class uses.
        private Component component = null;

        private EventManager() => component = new Component();

        // Use C# finalizer syntax for finalization code.
        // This finalizer will run only if the Dispose method
        // does not get called.
        // It gives your base class the opportunity to finalize.
        // Do not provide finalizer in types derived from this class.
        ~EventManager()
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(disposing: false) is optimal in terms of
            // readability and maintainability.
            Dispose(disposing: false);
        }

        public static EventManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_lockObj)
                    {
                        if (_instance == null)
                            _instance = new EventManager();
                    }
                }
                return _instance;
            }
        }

        /// <summary>
        /// Add listener
        /// </summary>
        /// <typeparam name="TDelegate">Specify the delegate type.</typeparam>
        /// <param name="newDelegate">Delegate to be added.</param>
        /// <exception cref="ArgumentNullException">parameter null exception.</exception>
        public void AddListener<TDelegate>(TDelegate newDelegate) where TDelegate : Delegate
        {
            if (newDelegate == null) throw new ArgumentNullException(nameof(newDelegate));
            if (_dicDelegates.ContainsKey(typeof(TDelegate))) return;
            handle = new IntPtr(1);
            _dicDelegates.Add(typeof(TDelegate), newDelegate);
        }

        /// <summary>
        /// Remove listener
        /// </summary>
        /// <typeparam name="TDelegate">Specify the delegate type.</typeparam>
        /// <param name="oldDelegate">Remove old delegates.</param>
        /// <exception cref="ArgumentNullException">parameter null exception.</exception>
        public void RemoveListener<TDelegate>(TDelegate oldDelegate) where TDelegate : Delegate
        {
            if (oldDelegate == null) throw new ArgumentNullException(nameof(oldDelegate));
            var delegateType = oldDelegate.GetType();
            if (!delegateType.IsInstanceOfType(typeof(TDelegate))) return;
            Delegate tempDelegate = null;
            if (_dicDelegates.TryGetValue(delegateType, out tempDelegate))
            {
                if (tempDelegate == null)
                {
                    _dicDelegates.Remove(delegateType);
                }
                else
                {
                    _dicDelegates[delegateType] = tempDelegate;
                }
            }
        }

        /// <summary>
        /// Triggers a delegate of the same type.
        /// </summary>
        /// <typeparam name="TDelegate"></typeparam>
        /// <param name="sender">trigger source object.</param>
        /// <param name="eventArgs">event args.</param>
        /// <exception cref="ArgumentNullException">parameter null exception.</exception>
        public void Dispatch<TDelegate>(object sender, EventArgs eventArgs) where TDelegate : Delegate
        {
            if (sender == null) throw new ArgumentNullException(nameof(sender));
            if (eventArgs == null) throw new ArgumentNullException(nameof(eventArgs));
            if (!_dicDelegates.ContainsKey(typeof(TDelegate))) return;
            _dicDelegates[typeof(TDelegate)].DynamicInvoke(sender, eventArgs);
        }

        /// <summary>
        /// Clear all listeners.
        /// </summary>
        public void Clear() => _dicDelegates.Clear();

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(disposing: true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SuppressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the
        // runtime from inside the finalizer and you should not reference
        // other objects. Only unmanaged resources can be disposed.
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if (disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }

                // Call the appropriate methods to clean up
                // unmanaged resources here.
                // If disposing is false,
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;
            }
        }
    }
代码语言:javascript
复制
    /// <summary>
    /// Event manager interface.
    /// </summary>
    public interface IEventManager
    {
        /// <summary>
        /// Adding Event Listeners.
        /// </summary>
        /// <typeparam name="TDelegate">Generic delegate.</typeparam>
        /// <param name="newDelegate">New delegate that needs to be injected.</param>
        void AddListener<TDelegate>(TDelegate newDelegate) where TDelegate : Delegate;

        /// <summary>
        /// Removing Event Listening.
        /// </summary>
        /// <typeparam name="TDelegate">Generic delegate.</typeparam>
        /// <param name="oldDelegate">Need to remove an existing delegate.</param>
        void RemoveListener<TDelegate>(TDelegate oldDelegate) where TDelegate : Delegate;

        /// <summary>
        /// Triggers notifications of the same event type based on the listening event type.
        /// </summary>
        /// <typeparam name="TDelegate">generic delegate.</typeparam>
        /// <param name="sender">Event handler.</param>
        /// <param name="eventArgs">Event args.</param>
        void Dispatch<TDelegate>(object sender, EventArgs eventArgs) where TDelegate : Delegate;

        /// <summary>
        /// Remove all injected delegates.
        /// </summary>
        void Clear();
    }
代码语言:javascript
复制
//抛出异常
EventManager.Instance.Dispatch<Action<object, ExceptionEventArgs>>(this, new ExceptionEventArgs(ex));

//接收异常
EventManager.Instance.AddListener((sender,exception)=>{ ...... });
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-07-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JusterZhu 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、概要
    • 项目地址
    • 二、详细内容
      • 那么我们简单分析一下设计的解决方案要满足什么样的条件:
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档