C#反射可以让我们在运行时根据需要动态加载并调用其他程序集中的对象、函数和属性等,这对于某些需要动态处理对象的场景非常有用。而操作泛型和属性字段是其中的常见需求。下面是一份完整攻略:
一、加载dll文件
使用反射前,需要首先通过Assembly.Load()方法或者Assembly.LoadFile()方法或Assembly.LoadFrom()方法来加载需要操作的dll文件。这里以Assembly.LoadFile()方法为例:
string path = @"C:\SomeFolder\SomeAssembly.dll";
Assembly assembly = Assembly.LoadFile(path);
二、获取类型
获取需要操作的类类型,是使用反射的第二步。有两种方法可以做到。第一种方法是通过Assembly对象的GetType()方法,第二种方法是通过Assembly对象的GetExportedTypes()方法。
Type type1 = assembly.GetType("SomeNamespace.SomeClass");
Type[] types = assembly.GetExportedTypes();
Type type2 = types.FirstOrDefault(t => t.Name == "SomeClass");
三种方法中,GetType()方法最常用,但这个方法只能获取已加载的程序集的类型信息。
三、调用方法
获取到类型之后,可以使用Activator.CreateInstance()方法创建对象,或者使用Type.InvokeMember()方法调用方法。
// 创建对象
object instance = Activator.CreateInstance(type1);
// 调用方法
object result = type1.InvokeMember("SomeMethod", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, instance, new object[] { arg1, arg2 });
这里需要注意BindingFlags的用法,可以根据需要对方法进行分类,这里的例子是调用无返回值的方法,如果需要调用有返回值的方法,可以使用BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance | BindingFlags.ReturnValue。
四、调用泛型方法
调用泛型方法,需要结合MethodInfo.MakeGenericMethod()方法,将泛型方法实例化后进行调用:
MethodInfo genericMethod = type1.GetMethod("SomeGenericMethod");
MethodInfo method = genericMethod.MakeGenericMethod(typeof(SomeObjectOfType));
object result = method.Invoke(instance, new object[] { arg1, arg2 });
这里的MakeGenericMethod()方法中,需要传递泛型类型的类型参数。
五、访问属性字段
访问属性字段,可以使用Type.GetProperty获取属性信息,再使用PropertyInfo.GetValue()方法获取属性值,或者使用PropertyInfo.SetValue()方法为属性设置值。访问字段的方法同理,只需将Type.GetProperty改为Type.GetField。
// 获取属性
PropertyInfo propertyInfo = type1.GetProperty("SomeProperty");
// 获取属性值
object value = propertyInfo.GetValue(instance);
// 设置属性值
propertyInfo.SetValue(instance, newValue);
示例1:调用dll文件中的方法
假设有一个MathUtil类,其中包含了一个Factorial方法,可以计算阶乘。下面展示如何通过反射调用该方法。
public class MathUtil
{
public static int Factorial(int n)
{
if (n == 0)
return 1;
else
return n * Factorial(n - 1);
}
}
Assembly assembly = Assembly.LoadFile(@"path\to\MathUtil.dll");
Type mathUtilType = assembly.GetType("MathUtil");
MethodInfo factorialMethodInfo = mathUtilType.GetMethod("Factorial");
int result = (int)factorialMethodInfo.Invoke(null, new object[] { 5 });
Console.WriteLine(result);
注意,MathUtil类中的Factorial方法是静态方法,因此第一个参数传入null。
示例2:操作泛型
假设有一个GenericClass类,其中包含了一个泛型方法GetMax,可以返回两个参数中较大的一个。下面展示如何通过反射调用该方法。
public class GenericClass
{
public T GetMax<T>(T a, T b) where T : IComparable<T>
{
if (a.CompareTo(b) > 0)
return a;
else
return b;
}
}
Assembly assembly = Assembly.LoadFile(@"path\to\MyLibrary.dll");
Type type = assembly.GetType("GenericClass");
object obj = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod("GetMax");
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(typeof(double));
double result = (double)genericMethodInfo.Invoke(obj, new object[] { 1.1, 2.2 });
Console.WriteLine(result);
注意,GetMax方法中要求泛型类型继承自IComparable接口,因此这里的double可以正常使用CompareTo方法进行比较。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#反射调用dll文件中的方法操作泛型与属性字段 - Python技术站