【问题标题】:call c# class method by reflection with constructor using dependency injection使用依赖注入通过构造函数反射调用c#类方法
【发布时间】:2020-11-30 12:22:53
【问题描述】:
 var fileName = string.Format(@"{0}\{1}\{2}.dll", Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)),"ProviderDLLS", $"UtilityPayments.Providers.TestProvider");
 if (!File.Exists(fileName)) return null;
 AssemblyName an = AssemblyName.GetAssemblyName(fileName);
 Assembly assembly = Assembly.LoadFile(fileName);
 Type objectType = assembly.GetType("UtilityPayments.Providers.TestProvider.Class1");
 IProviderProcessor remoteAssembly = (IProviderProcessor)Activator.CreateInstance(objectType);
 return await remoteAssembly.GetProviderData();

我调用类方法,它使用反射实现IProviderProcessor 接口。 如果我在 Class1 类中声明一个构造函数并使用 DI 添加接口,我会收到此错误:

System.MissingMethodException:未定义无参数构造函数 对于“UtilityPayments.Providers.TestProvider.Class1”类型。在 System.RuntimeType.CreateInstanceDefaultCtorSlow(布尔 publicOnly, Boolean wrapExceptions, Boolean fillCache) 在 System.RuntimeType.CreateInstanceDefaultCtor(布尔 publicOnly, 布尔型 skipCheckThis、布尔型 fillCache、布尔型 wrapExceptions)
在 System.Activator.CreateInstance(类型类型,布尔非公共, Boolean wrapExceptions)

Class1构造函数:

public class Class1: IProviderProcessor
{
    private readonly IProviderService _providerService;
    
    public Class1(IProviderService providerService)
    {
        _providerService = providerService;
    }
    
}

如果我想在构造函数中注入接口,如何使用反射调用Class1 方法? 如果我删除构造函数,代码可以正常工作,但我需要使用应用程序 Class1 中的其他功能,这些功能是使用依赖注入实现的。

【问题讨论】:

  • 您的代码根本没有引用容器。您的代码如何知道要为您的班级提供什么 IServiceProvider?

标签: c# .net-core reflection dependency-injection


【解决方案1】:

我必须解决这个几乎完全一样的问题。 我发现最简单但也许不是最好的方法是使用 ServiceProvider。

在您想要运行代码的任何类中添加一个 ServiceProvider:

private protected IServiceProvider _serviceProvider;

你可以正常注入:

public YourClass(IServiceProvider services){_serviceProvider = services;}

然后替换:

IProviderProcessor remoteAssembly = (IProviderProcessor)Activator.CreateInstance(objectType);

与:

IProviderProcessor remoteAssembly = (IProviderProcessor)_serviceProvider.GetRequiredService(objectType);

【讨论】:

  • 谢谢,我使用 _serviceProvider 来获取 ProviderService 类的实例
【解决方案2】:

感谢您的帮助。我使用 serviceprovider 解决了这个问题,以获取注入 Class1 类的构造函数中的接口实例。

var fileName = string.Format(@"{0}\{1}\{2}.dll", Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)),"ProviderDLLS", $"UtilityPayments.Providers.TestProvider");
if (!File.Exists(fileName)) return null;
AssemblyName an = AssemblyName.GetAssemblyName(fileName);
Assembly assembly = Assembly.LoadFile(fileName);
Type objectType = assembly.GetType("UtilityPayments.Providers.TestProvider.Class1");
var constructors = objectType.GetConstructors();
var firstConstrutor = constructors.FirstOrDefault(); //assume we will have only one constructor
var parameters = new List<object>();

foreach (var param in firstConstrutor.GetParameters())
{
   var service = _serviceProvider.GetService(param.ParameterType);//get instance of the class
   parameters.Add(service);
}

IProviderProcessor remoteAssembly = (IProviderProcessor)Activator.CreateInstance(objectType,parameters.ToArray());
return await remoteAssembly.GetProviderData();

【讨论】:

  • 这很好,但是 DI 大部分时间都使用接口,这意味着可以有多个相同的实现,或者像 IOptions 之类的泛型实现(以及类似的东西具有依赖他们自己有依赖关系)。为了使它成为一个包罗万象的东西,尾调用递归将是荒谬的,并且可能存在要求成为单例的内置函数。这东西很难,到目前为止,我正在尝试自己解决这个问题,运气不佳
【解决方案3】:

Activator.CreateInstance 有一个原型,允许您传递构造函数参数。它们需要按顺序包含在对象数组中,如下所示。

当然,您需要能够以某种方式获得对提供者服务的引用。

var providerService = GetProviderServiceFromSomewhere();
var arguments = new object[] { providerService };
IProviderProcessor remoteAssembly = (IProviderProcessor)Activator.CreateInstance(objectType, arguments);

【讨论】:

  • 谢谢,我使用 _serviceProvider 来获取 DI 类的实例并将其作为数组传递。
猜你喜欢
  • 1970-01-01
  • 2019-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 2011-12-29
相关资源
最近更新 更多