使用 ctor 注入和 ServiceProvider 创建实例
Create instance using ctor injection and ServiceProvider
我知道有 IServiceCollection
接口可以注册我的服务,IServiceProvider
可以实例化服务。
如何根据使用注册服务的指定类型实例化 class?
class MyClass
{
public MyClass(ISomeService someService) { }
}
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ISomeService, SomeService>()
MyClass instance = CreateInstance(typeof(MyClass));
object CreateIntance(Type type)
{
???
}
例如ASP.NET Core如何创建控制器实例?
我已经天真地实现了激活器,但是 .NET Core 中不是已经有了这样的东西吗?
private static object CreateInstance(Type type, IServiceProvider serviceProvider)
{
var ctor = type.GetConstructors()
.Where(c => c.IsPublic)
.OrderByDescending(c => c.GetParameters().Length)
.FirstOrDefault()
?? throw new InvalidOperationException($"No suitable contructor found on type '{type}'");
var injectionServices = ctor.GetParameters()
.Select(p => serviceProvider.GetRequiredService(p.ParameterType))
.ToArray();
return ctor.Invoke(injectionServices);
}
}
编辑:这是我的场景。我重构了一些实现此接口的遗留代码。
public interface IEventDispatcher
{
void RegisterHandler(Type handler);
void Dispatch(DomainEvent @event);
}
在 Dispatch 方法实现中,我创建了处理程序的实例:
public class InMemoryBus : IEventDispatcher
{
private readonly List<Type> _handlers = new List<Type>();
private readonly Func<Type, object> activator;
/// <param name="activator">Used to create instance of message handlers</param>
public InMemoryBus(Func<Type, object> activator)
{
this.activator = activator;
}
public void Dispatch(DomainEvent @event)
{
Type messageType = message.GetType();
var openInterface = typeof(IHandleMessages<>);
var closedInterface = openInterface.MakeGenericType(messageType);
var handlersToNotify = from h in _handlers
where closedInterface.GetTypeInfo().IsAssignableFrom(h.GetTypeInfo())
select h;
foreach (Type h in _handlersToNotify)
{
//this is the tricky part
var handlerInstance = activator(h);
closedInterface.GetTypeInfo()
.GetMethod(nameof(IHandleMessages<T>.Handle))
.Invoke(handlerInstance, new[] { message });
}
}
public void RegisterHandler(Type type) => _handlers.Add(type);
}
给出
public class MyClass {
public MyClass(ISomeService someService) {
//...
}
}
您需要构建整个对象图,以便提供者知道它可以创建什么
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ISomeService, SomeService>()
serviceCollection.AddTransient<MyClass>();
IServiceProvider provider = serviceCollection.BuildServiceProvider();
MyClass instance = provider.GetService<MyClass>();
调用 provider.GetService<MyClass>()
时,提供程序将初始化 MyCLass
,解决进程中的所有依赖关系。
才是正确的做事方式。
For example, how does ASP.NET Core creates controller instances?
如果您不想注册服务,您可以使用我们所说的 "type activation"。有一种名为 ActivatorUtilities 的类型,它具有您想要的辅助方法。您调用 ActivatorUtilities.CreateInstance(serviceProvider, type)
,它将使用指定的服务提供商激活该类型。
我知道有 IServiceCollection
接口可以注册我的服务,IServiceProvider
可以实例化服务。
如何根据使用注册服务的指定类型实例化 class?
class MyClass
{
public MyClass(ISomeService someService) { }
}
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ISomeService, SomeService>()
MyClass instance = CreateInstance(typeof(MyClass));
object CreateIntance(Type type)
{
???
}
例如ASP.NET Core如何创建控制器实例?
我已经天真地实现了激活器,但是 .NET Core 中不是已经有了这样的东西吗?
private static object CreateInstance(Type type, IServiceProvider serviceProvider)
{
var ctor = type.GetConstructors()
.Where(c => c.IsPublic)
.OrderByDescending(c => c.GetParameters().Length)
.FirstOrDefault()
?? throw new InvalidOperationException($"No suitable contructor found on type '{type}'");
var injectionServices = ctor.GetParameters()
.Select(p => serviceProvider.GetRequiredService(p.ParameterType))
.ToArray();
return ctor.Invoke(injectionServices);
}
}
编辑:这是我的场景。我重构了一些实现此接口的遗留代码。
public interface IEventDispatcher
{
void RegisterHandler(Type handler);
void Dispatch(DomainEvent @event);
}
在 Dispatch 方法实现中,我创建了处理程序的实例:
public class InMemoryBus : IEventDispatcher
{
private readonly List<Type> _handlers = new List<Type>();
private readonly Func<Type, object> activator;
/// <param name="activator">Used to create instance of message handlers</param>
public InMemoryBus(Func<Type, object> activator)
{
this.activator = activator;
}
public void Dispatch(DomainEvent @event)
{
Type messageType = message.GetType();
var openInterface = typeof(IHandleMessages<>);
var closedInterface = openInterface.MakeGenericType(messageType);
var handlersToNotify = from h in _handlers
where closedInterface.GetTypeInfo().IsAssignableFrom(h.GetTypeInfo())
select h;
foreach (Type h in _handlersToNotify)
{
//this is the tricky part
var handlerInstance = activator(h);
closedInterface.GetTypeInfo()
.GetMethod(nameof(IHandleMessages<T>.Handle))
.Invoke(handlerInstance, new[] { message });
}
}
public void RegisterHandler(Type type) => _handlers.Add(type);
}
给出
public class MyClass {
public MyClass(ISomeService someService) {
//...
}
}
您需要构建整个对象图,以便提供者知道它可以创建什么
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ISomeService, SomeService>()
serviceCollection.AddTransient<MyClass>();
IServiceProvider provider = serviceCollection.BuildServiceProvider();
MyClass instance = provider.GetService<MyClass>();
调用 provider.GetService<MyClass>()
时,提供程序将初始化 MyCLass
,解决进程中的所有依赖关系。
For example, how does ASP.NET Core creates controller instances?
如果您不想注册服务,您可以使用我们所说的 "type activation"。有一种名为 ActivatorUtilities 的类型,它具有您想要的辅助方法。您调用 ActivatorUtilities.CreateInstance(serviceProvider, type)
,它将使用指定的服务提供商激活该类型。