C#反射概念及应⽤场景
元数据(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这⼀步是⼀样的。所以只要在不同运⾏环境的计算机上安装对应的不同的C
LR/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);
}
}
}
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。