메서드에 PreCondition/PostCondition 구현하기

닷넷 프레임워크를 통하여 응용프로그램을 개발할 때, 특히 Windows Forms 기반의 다중 스레드 프로그램을 구성할 때 자주 적용되는 패턴이 하나 있다면, 단일 메서드를 가지고 PreCondition/PostCondition으로 양분하는 패턴이 있을 것입니다. 예를 들면 다음과 같습니다.


 


private void MyForm_Load(object sender, EventArgs e)
{


    if (this.InvokeRequired)


    {


         this.Invoke(new EventHandler(MyForm_Load), new object[] { sender, e });


         return;


    }


    // 실제 메서드 코딩
}


 


위와 같이 조건에 따라서, 같은 메서드를 상태에 변화를 가하여 다시 호출하는 기법은 Windows Forms 뿐만 아니라 일반적인 응용프로그램에서도 자주 활용될 수 있는 기법이 될 것입니다. 사실, 위와 같은 코드는 어려울 것이 없겠습니다만 저는 이를 일반화할 수 있는 방법을 고민하던 중에, Reflection과 Interop을 이용할 수 있다는 것을 발견하였습니다.


 




using System;
using System.Reflection;


namespace dotForex.Test
{
    class Program
    {
        static bool needInvoke = true;


        static void Main(string[] args)
        {
            if (needInvoke)
            {
                Action<string[]> func = Delegate.CreateDelegate(
                    typeof(Action<string[]>),
                    MethodInfo.GetCurrentMethod() as MethodInfo) as Action<string[]>;
                needInvoke = false;
                func(args);
                return;
            }
            else
            {
                Console.WriteLine(“Test”);
            }


            return;
        }
    }
}


 


위의 코드에서 강조표시된 부분이 일반화에서 핵심이 되는 부분들입니다. Delegate 클래스의 CreateDelegate 메서드를 통하여, 생성할 대리자의 형식을 지정하고, 현재 메서드의 정보를 가져와서 이를 대입하는 방법입니다.


 


위와 같은 기법을 통하여 아래와 같이 Windows Forms의 스레드 안정성을 고려한 이벤트 핸들러 처리를 일반화하는 것도 가능합니다.


 




using System;
using System.Reflection;
using System.Windows.Forms;
using System.Runtime.InteropServices;


namespace dotForex.Application
{
    public sealed partial class ErrorReportForm : Form
    {
        public ErrorReportForm()
            : base()
        {
            this.InitializeComponent();
        }


        private object EnsureThreadSafe(MethodInfo targetMethod, Type targetDelegateType, params object[] arguments)
        {
            if (!this.InvokeRequired)
                throw new InvalidOperationException(“EnsureThreadSafe is not required at this time.”);


            if (targetMethod == null)
                throw new ArgumentNullException(“targetMethod”);


            if (targetDelegateType == null)
                throw new ArgumentNullException(“targetDelegateType”);


            if (!targetDelegateType.IsSubclassOf(typeof(Delegate)))
                throw new ArgumentException(“Selected type is not a delegate type.”, “targetDelegateType”);


            Delegate methodDelegate = Delegate.CreateDelegate(
                targetDelegateType,
                targetMethod);


            if (methodDelegate == null)
                throw new Exception(“Method cannot converted as delegate.”);


            return this.Invoke(methodDelegate, arguments);
        }


        private void ErrorReportForm_Load(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.EnsureThreadSafe(MethodInfo.GetCurrentMethod() as MethodInfo, typeof(EventHandler), sender, e);
                return;
            }


            // Method Coding Here
        }
    }
}


 


 

댓글 남기기