使用 Microsoft.Extensions.DependencyInjection,我能否在提供额外的构造函数参数的同时解析类型并构造实例? [英] With Microsoft.Extensions.DependencyInjection, can I resolve the type and construct an instance while providing extra constructor parameters?

查看:21
本文介绍了使用 Microsoft.Extensions.DependencyInjection,我能否在提供额外的构造函数参数的同时解析类型并构造实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Microsoft.Extensions.DependencyInjection,我能否一次性解析类型并构造实例,同时提供额外的构造函数参数?

我想要做的很容易通过例子来说明.下面,在 CreateSomethingWithContext 中,我需要使用 ActivatorUtilities.CreateInstance 来调用参数化构造函数,但我不知道 ISomething<的具体类型/code> 提前.

我可以使用 serviceProvider.GetRequiredService 来解析类型并创建一个默认实例,但是我无法传递 context 参数.

我可以使用 工厂版本的AddTransient,但已经使用了AddTransient的代码来创建默认的代码,这会破坏代码>

下面,一个可能的麻烦(我不喜欢)是创建一个 Something 的冗余默认实例,只是为了找出它的类型并将其传递给 ActivatorUtilities.CreateInstance,连同 context 参数.

有更好的方法吗?澄清一下,我无法控制实现 ISomething/Something 的实际库.

使用系统;使用 Microsoft.Extensions.DependencyInjection;命名空间应用{公共接口 ISomething{void DoSomething() =>Console.WriteLine(nameof(DoSomething));}公共类东西:ISomething{公共东西()=>Console.WriteLine($"{this.GetType().Name} created");公共东西(对象上下文)=>Console.WriteLine($"{this.GetType().Name} created with {context}");}静态类程序{私有静态 IServiceProvider BuildServices() =>新服务集合().AddTransient().BuildServiceProvider();静态 ISomething CreateSomething(IServiceProvider serviceProvider) =>serviceProvider.GetRequiredService();静态 ISomething CreateSomethingWithContext(IServiceProvider serviceProvider, object context){//首先我需要一个 ISomething 的实例,只是为了学习它的具体类型var something = serviceProvider.GetRequiredService();var type = something.GetType();//现在我有了类型,我可以使用 ActivatorUtilities.CreateInstancevar something2 = (ISomething)ActivatorUtilities.CreateInstance(服务提供者,类型,上下文);返回东西2;}静态无效主(){var serviceProvider = BuildServices();创建东西(服务提供者);CreateSomethingWithContext(serviceProvider, Guid.NewGuid());}}}

解决方案

就我个人而言,我同意你不想用 ActivatorUtilities.CreateInstance 来做这件事——虽然它会起作用,但如果构造函数的签名发生变化,你最终会遇到运行时错误,我确信编译时错误会更可取.

为什么不注册一个完全独立的工厂 用于使用上下文构造对象 - 保持 AddTransient() 注册不变,以便所有依赖默认构造函数的调用代码仍然可以工作,并在需要插入 上下文?

With Microsoft.Extensions.DependencyInjection, can I resolve the type and construct an instance while providing extra constructor parameters, in one go?

What I'd like to do is easy to illustrate by example. Below, in CreateSomethingWithContext I need to use ActivatorUtilities.CreateInstance to call a parameterized constructor, but I don't know the concrete type for ISomething in advance.

I could use serviceProvider.GetRequiredService to resolve the type and create a default instance, but then I couldn't pass context parameter.

I could use a factory version of AddTransient, but that would break the code which already uses GetRequiredService to create default instances.

Below, a possible kludge (which I dislike) is to create a redundant default instance of Something only to figure out its type and pass it to ActivatorUtilities.CreateInstance, along with the context parameter.

Is there a better way of doing this? To clarify, I have no control over the actual library that implements ISomething/Something.

using System;
using Microsoft.Extensions.DependencyInjection;

namespace App
{
  public interface ISomething
  {
    void DoSomething() => Console.WriteLine(nameof(DoSomething));    
  }  
  
  public class Something: ISomething
  {
    public Something() =>
      Console.WriteLine($"{this.GetType().Name} created");

    public Something(object context) =>
      Console.WriteLine($"{this.GetType().Name} created with {context}");
  }

  static class Program
  {
    private static IServiceProvider BuildServices() => new ServiceCollection()
      .AddTransient<ISomething, Something>()
      .BuildServiceProvider();

    static ISomething CreateSomething(IServiceProvider serviceProvider) =>
      serviceProvider.GetRequiredService<ISomething>();

    static ISomething CreateSomethingWithContext(IServiceProvider serviceProvider, object context) 
    {
      // first I need an instance of ISomething, only to learn its concrete type for
      var something = serviceProvider.GetRequiredService<ISomething>();
      var type = something.GetType();  
      // now that I have the type, I can use ActivatorUtilities.CreateInstance
      var something2 = (ISomething)ActivatorUtilities.CreateInstance(
        serviceProvider, type, context);
      return something2;
    }

    static void Main()
    {
      var serviceProvider = BuildServices();
      CreateSomething(serviceProvider);
      CreateSomethingWithContext(serviceProvider, Guid.NewGuid());
    }
  }
}

解决方案

Personally, I agree with you about not wanting to do this with ActivatorUtilities.CreateInstance - although it will work, if ever the constructor's signature changes you'd end up getting a runtime error, and I'm sure a compile time error would be preferable.

Why not register a completely separate factory for constructing your object with the context - Leave the AddTransient() registration untouched so that all calling code that relies on the default constructor would still work, and use newly created factory where you need to insert your context?

这篇关于使用 Microsoft.Extensions.DependencyInjection,我能否在提供额外的构造函数参数的同时解析类型并构造实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆