2017-08-18 20 views
0

我知道有IServiceCollection接口可以注册我的服务,IServiceProvider可以实例化服务。使用ctor注入和ServiceProvider创建实例

如何基于指定类型实例化一个类,该类使用已注册的服务?

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核心中是不是有这样的东西?

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); 
} 

在调度方法实现我创建了处理程序实例:鉴于

public class MyClass { 
    public MyClass(ISomeService someService) { 
     //... 
    } 
} 

你需要建立整个对象图

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); 
} 
+0

DI框架将为您做到这一点,只需将参数传递给您的构造函数。 – DavidG

+0

serviceProvider.GetService ()返回null。在CreateInstance(Type)方法中,我不知道编译时的参数是什么 – Liero

+0

然后我们可能需要查看一些如何注册所有服务的实际代码。 – DavidG

回答

3

https://stackoverflow.com/a/45756192/45091是做事的正确方法。

例如,ASP.NET Core如何创建控制器实例?

如果你不想注册服务,你可以使用我们所说的“类型激活”。有一种叫做ActivatorUtilities的类型,它有你想要的帮助器方法。您致电ActivatorUtilities.CreateInstance(serviceProvider, type),它将使用指定的服务提供商激活该类型。

+0

有没有办法将“ActivatorUtilities.CreateInstance(type,serviceProvider)'与hybrid参数,有些来自一些自己提供的容器? –

+0

是的,它有额外的参数 – davidfowl

5

从而使提供者知道什么可以创建

var serviceCollection = new ServiceCollection(); 
serviceCollection.AddSingleton<ISomeService, SomeService>() 
serviceCollection.AddTransient<MyClass>(); 

IServiceProvider provider = serviceCollection.BuildServiceProvider(); 

MyClass instance = provider.GetService<MyClass>(); 

当调用provider.GetService<MyClass>()时,提供程序将初始化MyCLass,解析进程中的所有依赖项。

参考Introduction to Dependency Injection in ASP.NET Core

+0

是的,我知道当我注册MyClass和服务时,我将能够解决它。但是我真的必须注册所有可能的课程吗?首先,MyClass不是服务,所以我不确定它会记录到ServiceCollection。其次,Asp.net核心都没有将控制器注册到ServiceCollection中,然而它创建了控制器的实例 – Liero

+0

@Liero,您没有看到它何时注册控制器。并不意味着他们没有。当你调用'AddMvc'时,它会反映所有控制器并将它们添加到集合中。 Github上的源代码去检查 – Nkosi

+0

@Liero我认为你误解了DI在这里的“服务”是什么。 – DavidG

相关问题