C# 使用每个字符串的动态类型参数和强类型结果动态加载泛型 class
C# dynamically load generic class with dynamic type parameters per strings and strongly typed result
我正在尝试获取一个 JSON 文件,其中包含有关通用 [=45=](程序集、class 名称、类型参数名称)的数据,并动态加载和实例化指定的class。如果我为类型参数使用接口,我可以做到这一点。但是,实现细节不允许我走这条路,所以我需要使用特定类型参数 classes.
到目前为止我有以下代码:
var ci = Invoke.GetClassRef(@"D:\ROCT\Debug\x64 Core\Common Complex Functions.dll", "Namespace.Class");
Type[] typeArgs = { typeof(DoubleABCAry), typeof(FloatABCAry), typeof(Search3Range), typeof(object) };
var _model = ci.GetType().MakeGenericType(typeArgs);
var model = Activator.CreateInstance(_model) as ComplexBaseModel<IModelInput, IModelIOBase, ISearchDimension, object>;
model.Validate();
第 1 行:加载程序集并 class。没问题。
第 2 行:列出我需要通过 string[]
.
按名称指定的类型
第 4 行:DoubleABCAry
实现 IModelInput
; FloatABCAry
实施 IModelIOBase
,等等
第 4 行将对象转换为其基本定义(如图所示),这不是我想要的。我要 RGB255ToCIELAB : ComplexBaseModel<DoubleABCAry, FloatABCAry, Search3Range, object>
.
第 5 行表明 class 被正确理解。然而,class显然是在实现接口,而不是我需要的具体类型。
有没有办法实现这两个目标:
- 使用字符串名称指定每个类型参数。
- 最终
model
强类型化了?
我知道它可以通过动态编译代码实现,但这是我最后的选择。
我正在使用 C# 9 预览版。
所以我认为最终你的问题归结为你想要加载 dynamic
类型然后将它们视为 static
这样你就可以使用 instance.MyMethod()
语法调用方法.这是 not 可能的(AFAIC),因为 instance.MyMethod()
被编译为 IL,此时编译器不知道 instance
是什么。
因此,如果您无法知道要调用的方法是什么,则必须采用完全动态的方式,即使用反射 API 来调用正确的方法。
所以您不仅需要提供 class 名称,还需要提供方法名称或约定,例如always invoke method called 'Validate'
或类似的东西。
下面的一个简单列表说明了我的观点:
using System;
using System.Reflection;
namespace Shoes {
public interface IA { }
public class A : IA {}
public interface IB { }
public class B : IB {}
public class SomeKindOfModel<T1, T2> {
}
public class ConcreteModel<T1, T2> : SomeKindOfModel<T1, T2> {
public bool Validate() {
return true;
}
}
public class Program
{
public static void Main()
{
// since i don't have your Invoke.GetClassRef, i just did this, works in .net core
var type = Type.GetType($"Shoes.ConcreteModel`2");
var genType = type.MakeGenericType(new[] { typeof(A), typeof(B) });
var instance = Activator.CreateInstance(genType);
var result = genType.GetMethod("Validate", BindingFlags.Instance | BindingFlags.Public)
.Invoke(instance, null); // instead of null you can pass data etc.
Console.WriteLine(result); // prints True
}
}
}
我正在尝试获取一个 JSON 文件,其中包含有关通用 [=45=](程序集、class 名称、类型参数名称)的数据,并动态加载和实例化指定的class。如果我为类型参数使用接口,我可以做到这一点。但是,实现细节不允许我走这条路,所以我需要使用特定类型参数 classes.
到目前为止我有以下代码:
var ci = Invoke.GetClassRef(@"D:\ROCT\Debug\x64 Core\Common Complex Functions.dll", "Namespace.Class");
Type[] typeArgs = { typeof(DoubleABCAry), typeof(FloatABCAry), typeof(Search3Range), typeof(object) };
var _model = ci.GetType().MakeGenericType(typeArgs);
var model = Activator.CreateInstance(_model) as ComplexBaseModel<IModelInput, IModelIOBase, ISearchDimension, object>;
model.Validate();
第 1 行:加载程序集并 class。没问题。
第 2 行:列出我需要通过 string[]
.
第 4 行:DoubleABCAry
实现 IModelInput
; FloatABCAry
实施 IModelIOBase
,等等
第 4 行将对象转换为其基本定义(如图所示),这不是我想要的。我要 RGB255ToCIELAB : ComplexBaseModel<DoubleABCAry, FloatABCAry, Search3Range, object>
.
第 5 行表明 class 被正确理解。然而,class显然是在实现接口,而不是我需要的具体类型。
有没有办法实现这两个目标:
- 使用字符串名称指定每个类型参数。
- 最终
model
强类型化了?
我知道它可以通过动态编译代码实现,但这是我最后的选择。
我正在使用 C# 9 预览版。
所以我认为最终你的问题归结为你想要加载 dynamic
类型然后将它们视为 static
这样你就可以使用 instance.MyMethod()
语法调用方法.这是 not 可能的(AFAIC),因为 instance.MyMethod()
被编译为 IL,此时编译器不知道 instance
是什么。
因此,如果您无法知道要调用的方法是什么,则必须采用完全动态的方式,即使用反射 API 来调用正确的方法。
所以您不仅需要提供 class 名称,还需要提供方法名称或约定,例如always invoke method called 'Validate'
或类似的东西。
下面的一个简单列表说明了我的观点:
using System;
using System.Reflection;
namespace Shoes {
public interface IA { }
public class A : IA {}
public interface IB { }
public class B : IB {}
public class SomeKindOfModel<T1, T2> {
}
public class ConcreteModel<T1, T2> : SomeKindOfModel<T1, T2> {
public bool Validate() {
return true;
}
}
public class Program
{
public static void Main()
{
// since i don't have your Invoke.GetClassRef, i just did this, works in .net core
var type = Type.GetType($"Shoes.ConcreteModel`2");
var genType = type.MakeGenericType(new[] { typeof(A), typeof(B) });
var instance = Activator.CreateInstance(genType);
var result = genType.GetMethod("Validate", BindingFlags.Instance | BindingFlags.Public)
.Invoke(instance, null); // instead of null you can pass data etc.
Console.WriteLine(result); // prints True
}
}
}