Autofac 等同于 NInject 的 ToMethod() 和开放泛型
Autofac equivalent of NInject's ToMethod() with open generics
我正在尝试从 NInject 迁移到 Autofac,但我 运行 遇到了一个看似简单的问题。我想迁移这个 NInject 绑定:
Kernel.Bind(typeof(IOptions<>)).ToMethod(c => CreateOptions(c.Request.Service));
换句话说,当需要关闭 IOptions<>
时,请使用请求的类型调用 CreateOptions()
并让我创建实现。
我在 Autofac 中想到的最好的是:
- 创建
IOptions<>
的虚拟实现,让 Autofac 使用 RegisterGeneric()
构造它,然后在 OnActivating 事件中使用 ReplaceInstance()
。
- 创建一个
IRegistrationSource
按类型过滤然后调用我的工厂方法。
方法 (1) 似乎很愚蠢 - 当然我不必为了获取其类型而创建未使用的对象?
方法 (2) 没问题,但它是大量 代码(见下文),如果我想设置范围等,它会变得更大
在这两种情况下,简单地委托给工厂方法的代码量似乎很大。有没有更好的方法?
(为了完整起见,下面是我的 IRegistrationSource
。请注意必须覆盖两个抽象成员才能获得 NInject 功能。)
public abstract class DelegatingRegistrationSource : IRegistrationSource
{
protected abstract bool CanDelegate(Type limitType);
protected abstract DelegateActivator CreateDelegate(Type limitType);
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
if (!(service is IServiceWithType swt) || !CanDelegate(swt.ServiceType))
return Enumerable.Empty<IComponentRegistration>();
var registration = new ComponentRegistration(
Guid.NewGuid(),
CreateDelegate(swt.ServiceType),
new CurrentScopeLifetime(),
InstanceSharing.None,
InstanceOwnership.OwnedByLifetimeScope,
new[] { service },
new Dictionary<string, object>());
return new IComponentRegistration[] { registration };
}
public bool IsAdapterForIndividualComponents => false;
}
你让我想到了这个!
除了您现在已经掌握的机制之外,我想不出更好的方法来解决这个问题。你可以用开放的通用装饰器做一些事情,但你仍然需要虚拟类型,它并不比 OnActivating 解决方案好多少。
这就是某种 OnActivating 事件的用途,对激活实例进行高级替换。
如果您愿意在我们的回购协议 (http://github.com/autofac/autofac) 中提出一个问题作为功能请求,并提供所有细节,我愿意讨论 'ideal' 行为的外观如果我们将它添加到库中,以及用例是否足够常见以添加。
我正在尝试从 NInject 迁移到 Autofac,但我 运行 遇到了一个看似简单的问题。我想迁移这个 NInject 绑定:
Kernel.Bind(typeof(IOptions<>)).ToMethod(c => CreateOptions(c.Request.Service));
换句话说,当需要关闭 IOptions<>
时,请使用请求的类型调用 CreateOptions()
并让我创建实现。
我在 Autofac 中想到的最好的是:
- 创建
IOptions<>
的虚拟实现,让 Autofac 使用RegisterGeneric()
构造它,然后在 OnActivating 事件中使用ReplaceInstance()
。 - 创建一个
IRegistrationSource
按类型过滤然后调用我的工厂方法。
方法 (1) 似乎很愚蠢 - 当然我不必为了获取其类型而创建未使用的对象?
方法 (2) 没问题,但它是大量 代码(见下文),如果我想设置范围等,它会变得更大
在这两种情况下,简单地委托给工厂方法的代码量似乎很大。有没有更好的方法?
(为了完整起见,下面是我的 IRegistrationSource
。请注意必须覆盖两个抽象成员才能获得 NInject 功能。)
public abstract class DelegatingRegistrationSource : IRegistrationSource
{
protected abstract bool CanDelegate(Type limitType);
protected abstract DelegateActivator CreateDelegate(Type limitType);
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
if (!(service is IServiceWithType swt) || !CanDelegate(swt.ServiceType))
return Enumerable.Empty<IComponentRegistration>();
var registration = new ComponentRegistration(
Guid.NewGuid(),
CreateDelegate(swt.ServiceType),
new CurrentScopeLifetime(),
InstanceSharing.None,
InstanceOwnership.OwnedByLifetimeScope,
new[] { service },
new Dictionary<string, object>());
return new IComponentRegistration[] { registration };
}
public bool IsAdapterForIndividualComponents => false;
}
你让我想到了这个!
除了您现在已经掌握的机制之外,我想不出更好的方法来解决这个问题。你可以用开放的通用装饰器做一些事情,但你仍然需要虚拟类型,它并不比 OnActivating 解决方案好多少。
这就是某种 OnActivating 事件的用途,对激活实例进行高级替换。
如果您愿意在我们的回购协议 (http://github.com/autofac/autofac) 中提出一个问题作为功能请求,并提供所有细节,我愿意讨论 'ideal' 行为的外观如果我们将它添加到库中,以及用例是否足够常见以添加。