Unity を使って AOP

かな〜り前に、Enterprise Library の Policy Injection Application Block の機能が Unity に統合された、という記事を書きました。

変更された部分に触れただけで、使い方は変更前との差分しか書いていませんでした。過去記事と差分では全体の流れが把握しにくいので、(今更ですが)まとめておきます。自分のためにも。

Unity を使って AOP するサンプルはこれだ!

using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace UnityAopSample
{
    // Console にログを出力するクラス
    public class LogCallHandler : ICallHandler
    {
        public int Order { get; set; }
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            // メソッド呼び出し前のログを出力
            Console.WriteLine("Before {0}", input.MethodBase.Name);

            // インターセプトしたメソッドを呼び出す
            IMethodReturn result = getNext()(input, getNext);

            // メソッド呼び出し後のログを出力
            Console.WriteLine("After {0}", input.MethodBase.Name);

            return result;
        }
    }

    // インターセプトしてログを出力するクラスやメンバを指定するための属性
    public class LogCallHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new LogCallHandler();
        }
    }

    public interface IGreetingService
    {
        // Greet メソッドをインターセプトして、
        // Console にログを出力する
        [LogCallHandler]
        string Greet(string name);
    }

    public class GreetingService : IGreetingService
    {
        public string Greet(string name)
        {
            return string.Format("Hello, {0}!", name);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            UnityContainer container = new UnityContainer();

            // UnityContainer を拡張。
            // メソッドのインターセプトを可能にする。
            container.AddNewExtension<Interception>();

            // IGreetingService を実装するクラスのインスタンス
            // メソッドをインターセプトする。
            // インターセプトには透過プロキシを利用する。
            container.Configure<Interception>()
                .SetInterceptorFor<IGreetingService>(new TransparentProxyInterceptor());

            // Unity に型を登録
            container.RegisterType<IGreetingService, GreetingService>();

            // インスタンス生成         
            var service = container.Resolve<IGreetingService>();

            // メソッドがインターセプトされるかテスト
            var result = service.Greet("Ichiro");
            Console.WriteLine(result);

            Console.ReadLine();
        }
    }
}

f:id:griefworker:20091109173452p:image

言葉は不要。ただコードを読むのみ。