我正在尝试为AutoFac中某些标记的生命周期作用域提供不同的服务,但似乎无法掌握它。
我尝试使用Instance per matching lifetime scope, with default?中的自定义生存期,但这没用。
我写了一个测试来说明我要做什么:
[TestMethod]
public void NamedLifetimeTests()
{
var builder = new ContainerBuilder();
builder.Register(c => new ChildA()).As<Parent>().InstancePerLifetimeScope();
builder.Register(c => new ChildB()).As<Parent>().InstancePerMatchingLifetimeScope("system").PreserveExistingDefaults();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var parent = scope.Resolve<Parent>();
Assert.IsTrue(parent.GetType() == typeof(ChildA));
}
using (var scope = container.BeginLifetimeScope("system"))
{
var parent = scope.Resolve<Parent>();
Assert.IsTrue(parent.GetType() == typeof(ChildB));
}
}
这可能吗?
答案 0 :(得分:2)
解决方案可能是在创建范围时为生存期范围提供这些自定义服务。使用container.BeginLifetimeScope
创建新的生存期范围时,可以提供其他Action<ContainerBuilder>
参数来为此特定生存期范围定义一些自定义注册。
因此,对于您的代码,可以将其移至每个作用域的注册,而不是ChildB
的全局注册。看起来可能像这样:
[TestMethod]
public void NamedLifetimeTests()
{
var builder = new ContainerBuilder();
builder.Register(c => new ChildA()).As<Parent>().InstancePerLifetimeScope();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var parent = scope.Resolve<Parent>();
Assert.IsTrue(parent.GetType() == typeof(ChildA));
}
using (var scope = container.BeginLifetimeScope("system"), cb => { cb.RegisterType<ChildB>().As<Parent>(); }))
{
var parent = scope.Resolve<Parent>();
Assert.IsTrue(parent.GetType() == typeof(ChildB));
}
}
编辑: 避免注入生命周期范围是可以理解的。另一个解决方案可能是基于生命周期作用域标签选择适当的实现,类似于docs中所述的基于参数的实现选择:
// omitted ...
var builder = new ContainerBuilder();
builder.Register<Parent>(c =>
{
var currentScope = c.Resolve<ILifetimeScope>();
if (currentScope.Tag?.ToString() == "system")
{
return new ChildB();
}
return new ChildA();
}).InstancePerLifetimeScope();
var container = builder.Build();
// omitted ...
答案 1 :(得分:0)
以下扩展名可用于自动执行tdragon's answer。它还解决了嵌套范围问题。
<vector
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<group
android:scaleX="0.5"
android:scaleY="0.5"
android:pivotX="12"
android:pivotY="12">
<path
android:fillColor="@android:color/white"
android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
</group>
</vector>
用法
public static class RegistrationBuilderExtensions
{
public static IRegistrationBuilder<TLimit, SimpleActivatorData, SingleRegistrationStyle>
RegisterScopeResolver<TLimit>(this ContainerBuilder containerBuilder)
{
IRegistrationBuilder<TLimit, SimpleActivatorData, SingleRegistrationStyle> defineServiceScopes =
containerBuilder.Register(componentContext =>
{
var scope = componentContext.Resolve<ILifetimeScope>();
var registrations = componentContext.ComponentRegistry.RegistrationsFor(new TypedService(typeof(TLimit))).ToList();
Type activatorLimitType = registrations.Where(x => x.Lifetime is MatchingScopeLifetime).SingleOrDefault(x =>
(x.Lifetime as MatchingScopeLifetime).TagsToMatch.Contains(scope.Tag))?.Activator.LimitType;
if (activatorLimitType == null)
{
activatorLimitType = registrations.Single(x =>
{
return x.Lifetime.GetType() != typeof(MatchingScopeByFirstOccurenceLifetime<TLimit>) &&
x.Lifetime.GetType() != typeof(MatchingScopeLifetime);
})
.Activator
.LimitType;
}
return (TLimit) componentContext
.Resolve(activatorLimitType);
});
defineServiceScopes.RegistrationData.Sharing = InstanceSharing.Shared;
defineServiceScopes.RegistrationData.Lifetime = new MatchingScopeByFirstOccurenceLifetime<TLimit>();
return defineServiceScopes;
}
private class MatchingScopeByFirstOccurenceLifetime<TLimit> : IComponentLifetime
{
public ISharingLifetimeScope FindScope(ISharingLifetimeScope mostNestedVisibleScope)
{
if (mostNestedVisibleScope == null)
throw new ArgumentNullException(nameof(mostNestedVisibleScope));
var next = mostNestedVisibleScope;
while (next != null)
{
if (next.ComponentRegistry
.RegistrationsFor(new TypedService(typeof(TLimit)))
.Select(x => x.Lifetime)
.OfType<MatchingScopeLifetime>()
.Any(x => x.TagsToMatch.Contains(next.Tag)))
return next;
next = next.ParentLifetimeScope;
}
return mostNestedVisibleScope.RootLifetimeScope;
}
}
}
结果
ContainerBuilder containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<BaseA>().As<IMyBase>().InstancePerMatchingLifetimeScope("A").AsSelf();
containerBuilder.RegisterType<BaseB>().As<IMyBase>().InstancePerMatchingLifetimeScope("B").AsSelf();
containerBuilder.RegisterScopeResolver<IMyBase>();
var container = containerBuilder.Build();
using (var lifetimeScope = container.BeginLifetimeScope("A"))
{
Console.WriteLine(lifetimeScope.Resolve<IMyBase>());
using (var nestedLifetimeScope = lifetimeScope.BeginLifetimeScope())
{
Console.WriteLine(nestedLifetimeScope.Resolve<IMyBase>());
}
}
using (var lifetimeScope = container.BeginLifetimeScope("B"))
{
Console.WriteLine(lifetimeScope.Resolve<IMyBase>());
using (var nestedLifetimeScope = lifetimeScope.BeginLifetimeScope())
{
Console.WriteLine(nestedLifetimeScope.Resolve<IMyBase>());
}
}