元数据(MetaData)和反射(reflection):
一般情况下我们的程序都在处理数据的读、写、操作和展示。但是有些程序操作的数据不是数字、文本、图片,而是程序和程序类型本身的信息。
①元数据是包含程序以及类型信息的数据,它保存在程序的程序集当中。
②程序在运行的时候,可以查看其他程序集或者其本身的元数据。这个行为就是反射。.Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,例如:
Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。
Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。
MethodInfo包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。
诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。
Type类:
BCL声明了一个Type类型(它是抽象类),用来包含类型的特性。使用这个类的对象能让我们获取程序使用的类型的信息。
由于Type是抽象类,所以它不能被实例化。而是在运行时,CLR创建从Type(RuntimeType)派生的类型的实例。当我们要访问这些实例的时候,CLR不会返回派生类的引用而是返回Type基类的引用。
关于Type有如下重要的点:
①对于程序每一个需要用到的类型,CLR会穿件一个包含这个类型信息的Type类型的对象(真实的是上面说的派生的类型的实例)。
②程序中用到的每一个类型都会关联到独立的Type类的对两个象。
计算机执行过程:
对于计算机来讲,它只认识01010101之类的二进制代码,人类写的高级语言(如C#、JAVA等)计算机是没法识别的,所以需要将高级语言转化为01让计算机可以识别的二进制编码,中间是有一个过程的。就拿C#来讲,VS编译器会将编写好的代码进行编译,编译后会生成exe/dll文件,.Net Core里面已经不生成exe了,都是dll。dll和exe还需要CLR/JIT的即时编译成字节码,才能最终被计算机执行。有伙伴就会问为什么要编译2次呢,先编译到dll,再编译到字节码01呢,为什么不能一次性编译成字节码呢?因为我们写的是C#语言,但是真实运行的机器有很多种,可能是32位,也可能是64位,操作系统可能是windows、linux、unix等,不同的计算机不同的操作系统识别字节码的可能是不一样的,但是从高级语言编译成exe/dll这一步是一样的。所以只要在不同运行环境的计算机上安装对应的不同的CLR/JIT,就可以运行我们同一个exe/dll了。这里就大概讲下这样一个过程,后面会有章节详细讲解程序如何被计算机执行的。现在我们先关注编译生成的exe/dll,它包含2部分,分别是中间语言IL和源数据元数据metadata。IL里面包含我们写的大量的代码,比如说方法、实体类等。元数据metadata不是我们写的代码,它是编译器在编译的时候生成的描述,它可能是把命名空间、类名、属性名记录了一下,包括特性,反射可以动态的调取对象中的方法,这就是反射的好处。
反射使用:
获取对象类型的几种方法:
方法一:GetType方法,object类型包含了一个GetType方法,它可以用来返回事例的Type对象引用。由于所有的类都是继承自object类型,所以所有的类都可以调用GetType来获得Type类型对象的引用。
方法二:还可以通过typeof()方法来获取一个类型的Type对象引用。
方法三:根据程序集Assembly来获取程序集内的类型。
namespace Test
{
class BaseClass
{
public int BaseField = 0;
}
publice class test
{
private void main()
{
BaseClass baseClass = new BaseClass();
var type1 = baseClass.GetType();
var type2 = typeof(BaseClass);
var type3 = Assembly.GetExecutingAssembly().GetType("Test.BaseClass");
}
}
}
创建类型的构造函数:
Activator.CreateInstance (Type);//无参数
Activator.CreateInstance (Type, Object[]);//带参数
Activator.CreateInstance 泛型方法 ();//创建类型的一个实例,该类型由指定的泛型类型参数指定
获取程序集及所有类类型:
//运行目录下dll文件
Assembly dll = Assembly.LoadFrom("HelloWord.dll");// Assembly.LoadFrom("HelloWord");
var types=dll.GetTypes();
调用程序集类方法及委托调用:
namespace Webtest
{
public class ReflectTest
{
public string WriteString(string s,int i)
{
return "欢迎您," + s + "---" + i; ;
}
}
}
namespace Test
{
public class TestClass
{
delegate string TestDelegate(string value, int value1);
private void Main()
{
Assembly dll = Assembly.LoadFrom("HelloWord.dll"); // Assembly.LoadFrom("HelloWord");
object obj = dll.CreateInstance("Webtest.ReflectTest"); //获得程序集类实例
Type t = dll.GetType("Webtest.ReflectTest"); //获得程序集类类型
MethodInfo mi = t.GetMethod("WriteString"); //显示类具体的方法
object[] aa = { "使用的是带有参数的非静态方法", 2 };
//直接调用
string r= (string)mi.Invoke(obj, aa); //调用类实例方法委托
//委托调用
TestDelegate method = (TestDelegate)Delegate.CreateDelegate(typeof(TestDelegate), obj, "WriteString");
string result=method("str1", 2);
}
}
}
动态设置、获取类(Project)的属性值:
namespace Test
{
class BaseClass
{
public int BaseField { get; set; }
}
publice class test
{
private void main()
{
BaseClass baseClass = new BaseClass();
Type classtype = baseClass.GetType();
object classInstance = Activator.CreateInstance(classtype);
PropertyInfo id = classtype.GetProperty("BaseField");//获取属性信息
id.SetValue(classInstance, 1);//设置属性
var projectId = id.GetValue(classInstance);//读取属性
}
}
}
利用反射将类转结构体:
namespace Test
{
class BaseClass
{
public int BaseField { get; set; }
}
struct BaseStruct
{
public int BaseField;
}
publice class test
{
private void main()
{
BaseClass baseClass = new BaseClass();
Type classtype = baseClass.GetType();
object classInstance = Activator.CreateInstance(classtype);
PropertyInfo id = classtype.GetProperty("BaseField");
id.SetValue(classInstance, 1);
BaseStruct baseStruct = new BaseStruct();
object strcut= Activator.CreateInstance(baseStruct.GetType());
//方式一
FieldInfo[] fieldInfos = typeof(BaseStruct).GetFields();
foreach (FieldInfo StruValue in fieldInfos)
{
PropertyInfo classname = classtype.GetProperty(StruValue.Name);
var value = classname.GetValue(classInstance);
StruValue.SetValue(strcut, value);
}
//方式二
foreach (System.Reflection.PropertyInfo p in baseClass.GetType().GetProperties())
{
PropertyInfo classname = classtype.GetProperty(p.Name);
var value = classname.GetValue(classInstance);
FieldInfo stuctname = baseStruct.GetType().GetField(p.Name);
stuctname.SetValue(strcut, value);
}
}
}
}
参考:https://www.cnblogs.com/dcz2015/p/11058193.html