我想对当前运行的程序集中实现某些接口的对象调用一个方法。
我:
- 接口
IMyContract<T>
,其中T是一个类。 MyContractModel
和MyContractModel2
两种型号- 两个服务:
MyContractService
实现IMyContract<MyContractModel>
和MyContractService2
实现IMyContract<MyContractModel2>
- 在宿主体内注射
services.AddSingleton<IMyContract<MyContractModel>, MyContractService>()
和services.AddSingleton<IMyContract<MyContractModel2>, MyContractService2>()
.
我能够从程序集中获取适当的接口,并从依赖注入中加载服务实例,但我不能调用方法。由于编译器不知道类型,我得到了延迟绑定错误。
这是不可行的吗?如果是这样,你能提出其他的建议吗?感谢任何帮助。谢谢。
下面是我的代码:// Register services
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IMyContract<MyContractModel>, MyContractService>();
serviceCollection.AddSingleton<IMyContract<MyContractModel2>, MyContractService2>();
var serviceProvider = serviceCollection.BuildServiceProvider();
// Load all contract processors (that implement `IMyContract`) and invoke `Process` on them
var iContractPrcessor = typeof(IMyContract<>);
IEnumerable<Type> allTypesInThisAssembly = Assembly.GetExecutingAssembly().GetTypes();
foreach(Type type in allTypesInThisAssembly)
{
if (type.GetInterface(iContractPrcessor.Name.ToString()) != null)
{
// As expected in 1st iteration, produces IMyContract<MyContractModel>
Type implementedInterface = type.GetInterface(iContractPrcessor.Name.ToString());
// As expected in 1st iteration, produces MyContractService
var contractService = serviceProvider.GetService(implementedInterface);
MethodInfo method = iContractPrcessor.GetMethod("Process");
//This throws an exception: late bound operation exception
var result = (Task) method.Invoke(contractService, null);
await result.ConfigureAwait(false);
}
}
public interface IMyContract<T> where T : class
{
Task Process();
}
public class MyContractModel
{
public string Name { get; set; } = "";
}
public class MyContractService : IMyContract<MyContractModel>
{
public Task Process()
{
Console.WriteLine("MyContractService Process");
return Task.CompletedTask;
}
}
public class MyContractModel2
{
public string Name { get; set; } = "";
}
public class MyContractService2 : IMyContract<MyContractModel2>
{
public Task Process()
{
Console.WriteLine("MyContractService2 Process");
return Task.CompletedTask;
}
}
从typeof(IMyContract<>)
(iContractPrcessor
.)获得MethodInfo
MethodInfo method = iContractPrcessor.GetMethod("Process");
// ^^^ typeof(IMyContract<>) ^^^
…但是你试图用不同的类型来调用那个方法——实现接口的具体类型,比如typeof(MyContractService)
,它实现了IMyContract<MyContractModel>
。
var result = (Task) method.Invoke(contractService, null);
// ^^ object of concrete type ^^
所以你试图从一个类型IMyContract<>
调用另一个类型MyContractService
的方法。
相反,一旦你得到了具体类型,就得到了"过程"。
改变MethodInfo method = iContractPrcessor.GetMethod("Process");
MethodInfo method = contractService.GetType().GetMethod("Process");
现在你
- 获取实现接口的类型
- 从该类型获取方法
- 在该类型的实例上调用方法
可以更深入。所有这些都假设具体的服务都有一个名为"Process"的方法。它对应于接口方法。这可能不是真的。可能有多个"过程";方法。
如果你确信你在接口上有正确的方法,但你想确定你在类上有相应的方法,该怎么办?
你可以这样做:
// Get the interface type with the generic type specified
var genericInterfaceType = iContractPrcessor.MakeGenericType(t);
// Get the "Process" method on the interface.
var genericInterfaceMethod = genericInterfaceType.GetMethod("Process");
// Get a mapping of the interface's members to the concrete "target type" members.
InterfaceMapping interfaceMap = contractService.GetType()
.GetInterfaceMap(genericInterfaceType);
// Find the index of the interface's Process method
// in the interface method collection
var interfaceMethodIndex = interfaceMap.InterfaceMethods.ToList()
.IndexOf(genericInterfaceMethod);
// Get the method from the target type method collection with the same index.
// This is the method you want to invoke.
// It is the method on the service that implements the interface method.
var contractServiceMethod = interfaceMap.TargetMethods[interfaceMethodIndex];
我从来没有听说过InterfaceMap
,因为我从来没有尝试过解决这个问题。
尽管我是在回答这个问题,但我不能排除有一个完全不同的、更容易的解决方案。