17

Unity インターセプターを学習しようとしていますが、なかなかうまくいきません。

次のようなインターフェースがあるとします。

public interface IMyInterface
{
   void SomeMethod();
}

そして、次のようにそのインターフェースを実装する未知の数のクラスがあります。

public class SpecificClass1 : IMyInterface
{
   public void SomeMethod()
   {
       Console.WriteLine("Method Called");
   }
}

IMyInterface のすべてのインスタンス (列挙したくない) に対して、SomeMethod が呼び出されたときにインターセプターを実行する方法を探しています。

私に問題を引き起こしているのは、クラスの非列挙です。(すべてのクラスを列挙できる場合は、多くの例があります。)

Type Interception を読んだことがありますが、探していることができるかどうかはわかりません。

Unity の専門家は、私が探していることを行う方法を知っていますか?

4

3 に答える 3

20

InterceptionBehavior作成して特定のクラスに登録することができます。Invoke実行中のメソッドをフィルタリングできることに注意してくださいIMethodInvocation input

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using NUnit.Framework;

namespace UnitTests
{
    [TestFixture]
    public class ForTest
    {
        [Test]
        public void Test()
        {
            IUnityContainer container = new UnityContainer().AddNewExtension<Interception>();
            container.RegisterType<IMyInterface, SpecificClass1>(
                new Interceptor<InterfaceInterceptor>(),
                new InterceptionBehavior<MyInterceptionBehavior>());
            var myInterface = container.Resolve<IMyInterface>();
            myInterface.SomeMethod();
        }
    }

    public interface IMyInterface
    {
        void SomeMethod();
    }

    public class SpecificClass1 : IMyInterface
    {
        #region IMyInterface

        public void SomeMethod()
        {
            Console.WriteLine("Method Called");
        }

        #endregion
    }

    public class MyInterceptionBehavior : IInterceptionBehavior
    {
        public bool WillExecute
        {
            get { return true; }
        }

        #region IInterceptionBehavior

        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Enumerable.Empty<Type>();
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            IMethodReturn result = getNext()(input, getNext);
            Console.WriteLine("Interception Called");
            return result;
        }

        #endregion
    }
}

コンソール出力

Method Called
Interception Called

Unity による傍受の詳細

于 2012-08-10T21:50:21.090 に答える
9

@GSerjo は、うまく機能する Unity インターセプト アプローチの概要を説明しています。インターセプトの構成を自動化したい場合は、UnityContainerExtension を使用して、すべてのインターフェイス インターセプトと動作を自動的に結び付けることができます。より具体的なインターセプト (メソッド名、シグネチャ、戻り値など) を調べたい場合は、おそらくポリシー インジェクション (CallHandlers とのマッチング ルールを使用) を調べる必要があります。

したがって、この場合、コンテナ拡張は次のようになります。

public class UnityInterfaceInterceptionRegisterer : UnityContainerExtension
{
    private List<Type> interfaces = new List<Type>();
    private List<IInterceptionBehavior> behaviors = 
        new List<IInterceptionBehavior>();

    public UnityInterfaceInterceptionRegisterer(Type interfaceType, 
        IInterceptionBehavior interceptionBehavior)
    {
        interfaces.Add(interfaceType);
        behaviors.Add(interceptionBehavior);
    }

    public UnityInterfaceInterceptionRegisterer(Type[] interfaces, 
        IInterceptionBehavior[] interceptionBehaviors)
    {            
        this.interfaces.AddRange(interfaces);
        this.behaviors.AddRange(interceptionBehaviors);

        ValidateInterfaces(this.interfaces);
    }

    protected override void Initialize()
    {
        base.Container.AddNewExtension<Interception>();

        base.Context.Registering += 
            new EventHandler<RegisterEventArgs>(this.OnRegister);
    }

    private void ValidateInterfaces(List<Type> interfaces)
    {
        interfaces.ForEach((i) =>
        {
            if (!i.IsInterface)
                throw new ArgumentException("Only interface types may be configured for interface interceptors");
        }
        );
    }

    private bool ShouldIntercept(RegisterEventArgs e)
    {
        return e != null && e.TypeFrom != null && 
               e.TypeFrom.IsInterface && interfaces.Contains(e.TypeFrom);
    }

    private void OnRegister(object sender, RegisterEventArgs e)
    {
        if (ShouldIntercept(e))
        {
            IUnityContainer container = sender as IUnityContainer;

            var i = new Interceptor<InterfaceInterceptor>();
            i.AddPolicies(e.TypeFrom, e.TypeTo, e.Name, Context.Policies);

            behaviors.ForEach( (b) =>
                {
                    var ib = new InterceptionBehavior(b);
                    ib.AddPolicies(e.TypeFrom, e.TypeTo, e.Name, Context.Policies);
                }
            );
        }
    }
}

次に、次のように使用できます。

IUnityContainer container = new UnityContainer()
    .AddExtension(new UnityInterfaceInterceptionRegisterer(
        new Type[] { typeof(IMyInterface), 
                     typeof(IMyOtherInterface) }, 
        new IInterceptionBehavior[] { new MyInterceptionBehavior(), 
                                      new AnotherInterceptionBehavior() }
        ));

container.RegisterType<IMyInterface, SpecificClass1>();

var myInterface = container.Resolve<IMyInterface>();
myInterface.SomeMethod();

インターフェイスが登録されると、適切な傍受ポリシーもコンテナに追加されます。したがって、この場合、登録されたインターフェイスのタイプが IMyInterface または IMyOtherInterface の場合、ポリシーはインターフェイス インターセプト用にセットアップされ、インターセプション ビヘイビア MyInterceptionBehavior および AnotherInterceptionBehavior も追加されます。

Unity 3 (この質問/回答の後にリリースされた)は、この拡張機能が行うことを実行できる規則による登録機能を追加したことに注意してください (カスタム コードを記述する必要はありません)。Unity を使用した依存性注入の開発者ガイドの例:

var container = new UnityContainer();

container.AddNewExtension<Interception>();
container.RegisterTypes(
    AllClasses.FromLoadedAssemblies().Where(
      t => t.Namespace == "OtherUnitySamples"),
    WithMappings.MatchingInterface,
    getInjectionMembers: t => new InjectionMember[]
    {
      new Interceptor<VirtualMethodInterceptor>(),
      new InterceptionBehavior<LoggingInterceptionBehavior>()
    });
于 2012-08-12T07:29:33.443 に答える
0

傍受の設定には、複数のアクションが必要です。傍受されたタイプ、ポリシー、およびハンドラーの構成。

最初に、インターセプトがサポートされる状況のタイプに関する一般的な詳細については、アプリケーションでのインターセプトの使用を参照してください(たとえば、DI コンテナーの有無にかかわらず)。次に、サポートされているタイプ インターセプターの詳細については、タイプ インターセプトを参照してください。特に、クラスのタイプで使用できるインターセプターに注意してください (そうしないと、ハンドラーがトリガーされません)。

使用するインターセプターを決定したら、それを構成し、上記のリンクに従って十分なコール ハンドラーを作成します。この時点でまだ問題がある場合は、より詳細な質問を投稿してください。すでにこれを行っている場合は、構成とコードを投稿してください。「クラスの非列挙」では、実際に求めていることのヒントが得られません。「列挙」とは、属性主導のポリシーを割り当て、それなしでは目的を達成できないということですか?

于 2012-08-10T21:30:27.953 に答える