原文:https://blog.csdn.net/pengdayong77/article/details/47622235
在.Net 中,程序集(Assembly)中保存了元数据(MetaData)信息,因此就可以通过分析元数据来获取程序集中的内容,比如类,方法,属性等,这大大方便了在运行时去动态创建实例。
反射提供了封装程序集、模块和类型的对象(Type 类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。
主要用途:
- 动态加载DLL,实现插件机制。
- 实例化DLL中的类型。
- 执行后期绑定,访问在运行时创建的类型的方法。
今天我就介绍下后面的两个用途,其实最初的目的只是想根据配置文件中的值创建对应对象。
Dll
先上一段代码,这是要调用的ClassGreenerycn类,它被编译为DllDemo.dll。
using System; namespace DllDemo
{
public class ClassGreenerycn
{
public string Name { get; set; }
public bool IsTest { get; set; }
public void Hello()
{
Console.WriteLine(Name);
}
}
}
很简单的代码,就是一个类中有两个属性,Hello方法会向命令行中输出Name的名称。
使用反射创建Dll中的类实例并调用方法
现在再新建一个命令行的工程,该工程就一个用途,动态加载DllDemo.dll,然后实例化一个Name为Greenerycn,IsTest为True的对象,并调用Hello方法。
详细步骤如下:
1.引用反射的命名空间:
using System.Reflection;
2.动态加载Dll
动态加载Dll有3个函数:
public static Assembly Load(string assemblyString);
- 该方法传入的是Dll的名字,该Dll必须位于全局缓存GAC中才行,不然会报“System.IO.FileLoadException: 未能加载文件或程序集”的异常。
public static Assembly LoadFile(string path);
- 这个LoadFile最方便,参数就是dll的路径。
public static Assembly LoadFrom(string assemblyFile);
- 这个方法也可以,参数同样是dll路径。
3.获取ClassGreenerycn类的类型
var type = asm.GetType("DllDemo.ClassGreenerycn");
注意,这里需要完整的类型名称,包括签名的命名空间。
4.创建该类型的实例
var instance = asm.CreateInstance("DllDemo.ClassGreenerycn");
5.设置属性
type.GetProperty("Name").SetValue(instance, "http://greenerycn.cnblogs.com", null);
type.GetProperty("IsTest").SetValue(instance, true, null);
6.获取Hello方法
var method = type.GetMethod("Hello");
7.调用Hello方法
method.Invoke(instance, null);
8.编译运行
完整的代码
using System.Reflection;
namespace ReflectionDllDemo
{
class Program
{
static void Main(string[] args)
{
var asm = Assembly.LoadFile(@"d:\3_code\DotNet\DllDemo\DllDemo\bin\Debug\DllDemo.dll");
var type = asm.GetType("DllDemo.ClassGreenerycn");
var instance = asm.CreateInstance("DllDemo.ClassGreenerycn");
type.GetProperty("Name").SetValue(instance, "http://greenerycn.cnblogs.com", null);
type.GetProperty("IsTest").SetValue(instance, true, null);
var method = type.GetMethod("Hello");
method.Invoke(instance, null);
}
}
}
---------------------
//在外部动态库和本地类继承同一抽象类AbstractHi并实现同一接口interface 的情况下(甚至接口引用相同实体),主要用于加载不同类名,但实际签名相同的方法的类 //实体
public class Person
{
public string Name {get ;set}
}
//1.创建接口
public interface IHi
{
string SayHi();
Person GetPerson();
}
//2.抽象类继承接口
public abstract class AbstractHi : IHi
{
public abstract string SayHi();
public abstract Person GetPerson();
}
-----------------------------------------------
//3.动态库实现(dll文件)
public class DllDemo : AbstractHi
{
public override string SayHi()
{
return "Hi";
}
public override Person GetPerson()
{
var person =new Person ();
Person.Name = "MyName";
return person ;
}
}
------------------------------------------------
//4.加载动态库
/// <summary>
/// 返回操作对象,加载类名包含defaultClass字符串的类
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="defaultClass"></param>
/// <returns></returns>
public static T GetDllDemo<T>(string defaultClass) where T : class
{
try
{
var asm = Assembly.LoadFile(@"d:\3_code\DotNet\DllDemo\DllDemo\bin\Debug\DllDemo.dll");
var dllDemo = (from d in asm.DefinedTypes
where d.BaseType.FullName.Contains(defaultClass)
select d.FullName
).FirstOrDefault();
var type = asm.GetType(dllDemo);
return Activator.CreateInstance(type) as T;
}
catch (Exception ex)
{
throw ex;
}
} //.实例化
public class DllDemoBLL
{
private AbstractHi_DAL
public DllDemoBLL()
{
_DAL = GetDllDemo<AbstractHi>("DllDemo");
}
public string SayHi2()
{
return _DAL. SayHi();
}
public Person GetPerson2()
{
return _DAL. GetPerson();
}
}
//.调用
private DllDemoBLL _BLL = new DllDemoBLL(); public string SayHi3()
{
return _BLL.SayHi2();
//最终返回 "Hi"
}
public Person GetPerson3()
{
return _BLL.GetPerson2();
//最终返回 Person 属性Name=“MyName” 的实体
}