有没有办法将动作注册到DI容器(Autofac)?

时间:2014-07-18 03:04:00

标签: c# dependency-injection autofac

我有一种情况需要将Action注入到类的构造函数中。由于这种需要,我目前在我的应用程序中使用服务定位器模式,而不是简单地使用DI容器来实现它的目的。

以下是

的例子

RootPage.cs (主详情页面)

public RootPage()
{
    this.Master = new NavigationPage();
    this.Detail = new DetailPage(OnToggleRequest);
}
private Action OnToggleRequest()
{
    IsPresented = !IsPresented;
}

现在我要做的是将NavigationPageDetailPage注册到容器中,然后使用一些自定义逻辑来解析通用。

PseudoRootPage.cs

public RootPage()
{
    this.Master = MyApp.PageBuilder < NavigationPage > ();
    this.Detail = MyApp.PageBuilder < DetailPage > ();
}

问题在于我在DetailPage中需要的Action,以允许我切换导航菜单。

有没有办法将行动注册到DI容器?

另一个选项是使OnToggleRequest为internal static

3 个答案:

答案 0 :(得分:1)

听起来你需要的是Component Factory

DetailPage内,您可以创建一个委托属性,该属性将充当您网页的工厂。我没有这样做,但你可能会使这个静态(作为工厂方法/委托应该)。我基本上提供了Autofac给出的示例,为您的类型量身定制。

public delegate Shareholding Factory(Action toggleRequest);

然后使用IoC容器注册详细信息页面。

var builder = new ContainerBuilder();
builder.RegisterType<DetailPage>();
var container = builder.Build();

并最终在RootPage

中解析您的详情页面
var DetailPageFactory = container.Resolve<DetailPage.Factory>();
this.Detail = detailPageFactory.Invoke(OnToggleRequest);

希望这是你想要的。

答案 1 :(得分:1)

我不确定我是否100%理解与Master Detail Pages相关的所有复杂性,但是如何使用AutoFac 动态实例化

public class RootPage
{
   public RootPage(INavigationPage navigationPage,
      Func<Action, IDetailPage> detailPageFactory)
   {
      var detailPage = detailPageFactory(myAction);
   }
}

当AutoFac看到Func<Action, IDetailPage>构造函数参数时,它会在作为IDetailPage的工厂方法的委托中传递。

即。它会将您发送到工厂的Action参数传递给IDetailPage类型的构造函数。

可在此处找到更多详细信息:http://nblumhardt.com/2010/01/the-relationship-zoo/

答案 2 :(得分:0)

如果要注入的Action的实现是静态的,那真的很容易。通常我们不会将静态方法和注入放在一起,但是你依赖于可以替换的抽象,所以它根本不重要。

我建议声明与您的操作相对应的委托。否则,如果您需要注射并且两者都具有相同的签名,则它们无法区分。它还使您更清楚注册的是什么。

builder.Register<DelegateForSomeAction>(context => MyStaticClass.MyStaticMethod);

如果我们想要注入的动作属于必须解决的类,我们也可以这样做:

首先声明要使用的委托。这类似于声明一个接口,除了它只是为了动作:

public delegate int DoMath(Single value1, Single value2);

为了便于说明,这是一个带有实现委托的方法的类:

public class AddsNumbers 
{
    public Single Add(Single value1, Single value2)
    {
        return value1 + value2;
    }
}

然后注册包含要注入的方法的类型:

builder.RegisterType<AddsNumbers>();

然后注册委托的实现:

builder.RegisterType<AddsNumbers>();
builder.Register<DoMath>(c =>
{
    var componentContext = c.Resolve<IComponentContext>();
    var addsNumbers = componentContext.Resolve<AddsNumbers>();
    return addsNumbers.Add;
});

这告诉容器当您需要DoMath委托的实例时,它应该解析AddsNumbers的实例并返回其Add方法。

那有点乱。这是Autofac的扩展,使您无法编写相同的代码:

{ 
    public static IRegistrationBuilder<TDelegate, SimpleActivatorData, SingleRegistrationStyle> RegisterDelegate<TDelegate, TSource>( 
        this ContainerBuilder builder,  
        Func<TSource, TDelegate> extractDelegate,  
        string sourceComponentName = null,  
        string registeredComponentName = null)  
        where TDelegate : class
    {
        var registrationFunction = new Func<IComponentContext, TDelegate>(context => 
        { 
            var c = context.Resolve<IComponentContext>(); 
            var source = sourceComponentName == null 
                ? c.Resolve<TSource>() 
                : c.ResolveNamed<TSource>(sourceComponentName); 
            return extractDelegate(source); 
        }); 

        return registeredComponentName == null ? 
            builder.Register(registrationFunction) : 
            builder.Register(registrationFunction) 
                .Named<TDelegate>(registeredComponentName); 
    } 
}

现在实际的注册码更简单:

builder.RegisterDelegate<DoMath, AddsNumbers>(addsNumbers => addsNumbers.Add);

如果需要

,扩展方法还有一些额外的参数
  • 解决了委托所在的组件的命名实例
  • 命名您正在注册的委托组件
  • 两个

我更喜欢这种方法,因为如果你的类依赖于一个动作(委托)它应该只依赖于它,而不是取决于Autofac创建工厂所需的一些奇怪的接口。所有这些魔法应该被移动到组合根,然后该类正好得到它所要求的。

More details and examples