我有一种情况需要将Action注入到类的构造函数中。由于这种需要,我目前在我的应用程序中使用服务定位器模式,而不是简单地使用DI容器来实现它的目的。
以下是
的例子RootPage.cs (主详情页面)
public RootPage()
{
this.Master = new NavigationPage();
this.Detail = new DetailPage(OnToggleRequest);
}
private Action OnToggleRequest()
{
IsPresented = !IsPresented;
}
现在我要做的是将NavigationPage
和DetailPage
注册到容器中,然后使用一些自定义逻辑来解析通用。
PseudoRootPage.cs
public RootPage()
{
this.Master = MyApp.PageBuilder < NavigationPage > ();
this.Detail = MyApp.PageBuilder < DetailPage > ();
}
问题在于我在DetailPage中需要的Action,以允许我切换导航菜单。
有没有办法将行动注册到DI容器?
另一个选项是使OnToggleRequest为internal static
。
答案 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创建工厂所需的一些奇怪的接口。所有这些魔法应该被移动到组合根,然后该类正好得到它所要求的。