星期一, 6月 20, 2022

[C#] 不拋出 Exception 處理

整理公司內部 NLog 時發現某個工具 Class 內某段 Code,竟然使用 try catch 包起來不拋出 Excpeton,在 catch 內直接用 NLog Context 來接收 Exception,工具 Class 和 NLog 緊緊相依,把該段 Code 修改為變成透過事件傳出去,NLog 在事件內接收 Exception

範例程式

之前在 FB 上也看見類似案例,是使用者自訂控件內不拋出 Exception,但是要有機制通知外部程式,所以該範例會有兩個部分,分別為
  • 使用者自訂控件:自訂事件來處理
  • 自訂 Class :直接使用內建 UnhandledException 事件
就練習寫 Event 就是

使用者自訂控件
using System;
using System.Windows.Forms;

namespace UCExcpetion
{
    public partial class NOExcetionButton : UserControl
    {
        public NOExcetionButton()
        {
            InitializeComponent();
        }

        // Step3-1:自訂 EventHandler Event 寫法
        public event ExceptionEventHandler ExceptionOccur;
        // Step3-2:使用 Action Event 寫法
        // public event Action<object , ExceptionEventArgs> ExceptionOccur;

        // Step4:呼叫事件
        protected virtual void OnExceptionOccur(ExceptionEventArgs e)
        {
            if (ExceptionOccur != null)
                ExceptionOccur(this, e);
        }

        private void btnException_Click(object sender, EventArgs e)
        {
            try
            {
                throw new Exception("自訂控件內部發生 Exception");
            }
            catch (Exception ex)
            {
                // 透過事件向外通知
                ExceptionEventArgs eventArgs = new ExceptionEventArgs() { excpetion = ex };
                OnExceptionOccur(eventArgs);
            }
        }
    }

    // Step2:自訂 EventHandler 或是直接使用 Action 
    public delegate void ExceptionEventHandler(object sender, ExceptionEventArgs e);

    // Step1:自訂 EventArgs
    public class ExceptionEventArgs : EventArgs
    {
        public Exception excpetion { get; set; }
    }
}
自訂 Class 功能
using System;

namespace UCExcpetion
{
    public class ToolClass
    {
        // 使用 .NET 內建事件
        public event UnhandledExceptionEventHandler UnhandledException;

        public void ExceptionCreate()
        {
            try
            {
                throw new Exception("Toolclass 內部產生 Exception");
            }
            catch (Exception ex)
            {
                UnhandledExceptionEventArgs eventArgs = new UnhandledExceptionEventArgs(ex, false);
                // 透過 Invoke 直接呼叫 Event
                UnhandledException?.Invoke(this, eventArgs);
            }
        }

    }
}
呼叫上述兩者
using System;
using System.Windows.Forms;

namespace UCExcpetion
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            btnUCException.ExceptionOccur += BtnUCException_ExceptionOccur;
        }

        private void BtnUCException_ExceptionOccur(object sender, ExceptionEventArgs e)
        {
            MessageBox.Show(e.excpetion.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        private void btnToolClassExcpetion_Click(object sender, EventArgs e)
        {
            ToolClass t = new ToolClass();
            // 不去訂閱 UnhandledException Event 的話,ExceptionCreate() 產生的 Exception 是完全無感的 
            t.UnhandledException += (innerSender, args) =>
            {
                Exception ex = args.ExceptionObject as Exception;
                MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
            };
            t.ExceptionCreate();
        }
    }
}

畫面截圖

[C#] 不拋出 Exception 處理

沒有留言:

張貼留言