2012-08-10 77 views
17

的調用我正在嘗試學習Unity Interceptors,我正在努力學習它。使用Unity攔截所有對IMyInterface.SomeMethod

說我有一個這樣的接口:

public interface IMyInterface 
{ 
    void SomeMethod(); 
} 

我有數目不詳的實現像這樣的接口類:

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

我正在尋找一種方式說, 「對於IMyInterface的所有實例(我不想枚舉它們),當SomeMethod被稱爲運行我的攔截器時

它是類的非枚舉給我麻煩即(有很多例子,如果你可以列舉你所有的類。)

我已經閱讀過類型截取,但我似乎無法找出它是否會做我想找的。

任何Unity專家都知道如何去做我正在尋找的東西?

回答

0

設置攔截需要多個操作,攔截類型,策略和處理程序的配置。

有關支持截取的情況類型(例如,有或沒有DI容器)的一般細節,請參閱Using Interception in Applications。有關支持的攔截器的更多詳細信息,請參見Type Interception。尤其要注意攔截器可以用於你的類的類型(否則處理程序將永遠不會觸發)。

當你決定使用什麼攔截器時,配置它並根據上面的鏈接創建一個足夠的呼叫處理程序。如果您在這一點上仍然有問題,請發佈更詳細的問題。如果你已經這樣做了,請將配置和代碼發佈爲「非枚舉類」,根本不會提供任何提示。你有沒有機會用「枚舉」來指定你分配一個屬性驅動的策略,並且無法在沒有它的情況下實現你想要的?

18

你可以創建InterceptionBehavior然後在特定的類上註冊它。注意:您可以過濾在Invoke執行方法有關Interception with Unity

9

@GSerjo通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 

更多,概述了統一攔截的做法,效果很好。如果您想自動配置攔截,則可以使用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(在此問題/答案後發佈)添加了Registration by Convention功能,可以執行此擴展的功能(無需編寫任何自定義代碼)。來自Developer's Guide to Dependency Injection Using 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>() 
    });