文章引用
https://blog.csdn.net/Gnd15732625435/article/details/78587483
https://www.cnblogs.com/yaozhenfa/p/CSharp_Reflection_1.html
反射
.Net中类都被编译成IL,反射就是在可以在程序运行时获得类的信息(有哪些方法、字段、构造函数、父类以及类的类型等等。。),还可以动态的去创建对象、调用类成员。
反射提供了封装程序集、模块和类型的对象。每个类对应一个Type对象,每个方法对应一个MethodInfo对象,每个属性对应一个PropertyInfo....。这些就是类、方法、属性的"元数据"(meta data)。对象和这个类的对象没有直接的关系。这些"元数据对象"和成员有关,和对象无关,也就是每个成员对应一个对象。
使用场景
- 需要访问程序元数据的特性。
- 检查和实例化程序集中的类型。
- 在运行时构建新类型。使用System.Reflection.Emit中的类。
- 执行后期绑定,访问在运行时创建的类型的方法。【MSDN】
形象说明
地球的内部结构:地球的内部结构大体可以分为三层:地壳、地幔和地核。地壳是固体,地核是液体,地幔则是半液半固的结构(地理知识)。如何在地球表面不用深入地球内部就知道其内部结构呢?答案是:向地球发射“地震波”。地震波分两种,一种是横波,另一种是纵波。横波只能穿透固体,而纵波既可以穿透固体又可以穿透液体。通过在地面对纵波和横波的返回情况,我们就可以大体断定地球内部的构造了。
B型超声波:大家体检的时候都做过B超吧,B超可以透过肚皮探测到你的内脏的生理情况。这是如何做到的呢?答案是:它可以透过肚皮向你体内发射B型超声波,当超声波遇到内脏壁的时候就会产生一定的“回音”反射,然后把“回音”进行处理就可以显示出你的内脏的情况了。(部分细节不予追究)
大家注意到这两个例子的共同特点,就是从一个对象的外部去了解对象内部的构造,而且都是利用了波的反射功能。在.NET中的反射也可以实现从对象的外部来了解对象(或程序集)内部结构的功能,哪怕你不知道这个对象(或程序集)是什么,另外.NET中的反射还可以动态创建出对象并执行它其中的方法。
大家注意到这两个例子的共同特点,就是从一个对象的外部去了解对象内部的构造,而且都是利用了波的反射功能。在.NET中的反射也可以实现从对象的外部来了解对象(或程序集)内部结构的功能,哪怕你不知道这个对象(或程序集)是什么,另外.NET中的反射还可以动态创建出对象并执行它其中的方法。
反射是.NET中重要的机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌。另外我还可以直接创建对象,即使这个对象的类型在编译时还不知道。
反射的用途
(1)使用Assembly定义和加载程序集,加载在程序集中的所有模块以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
反射用到的命名空间
System.Reflection
System.Type
System.Reflection.Assembly
反射用到的主要类
System.Type 类--通过这个类可以访问任何给定数据类型的信息。
System.Reflection.Assembly 类--它可以用于访问给定程序集的信息,或者把这个程序集加载到程序中。
System.Type类用法
获取类信息对象Type
从对象获取:Type type= person.getType();
从类名获取:Type type = typeof(Person);
从全类名(命名空间+类名)获取:Type type = Type.GetType("反射.Person");
这上面三种方式主要是根据程序中所要探查的内容不一样,方式也就不一样。如果有一个对象,就用getType()获取,如果没有对象就用typeof来获取,如果要运行时通过配置文件等拿到的字符串来获得就要用Type.GetType("命名空间+类名");
Activator.CreateInstance(type)//使用无参数构造方法创建此类的对象(如果没有无参的构造函数会抛异常)。要求类必须由无参构造函数。相当于时new Person();有人可能会问明明可以new关键字来创建对象,为什么还要花这么一大圈来创建呢?
因为在真正业务中可能我们在这个代码的时候可能并不知道我们具体要执行的是哪一个类,所以才会有这样的用法。
插入一个小知识,是有可能出现的误区。
关于this
this代表“当前对象”,不是“当前类”,这个问题在类继承中尤其要注意。在父类中使用this,当创建一个子类对象的时候,去执行有关this的代码就是执行字类中的实现。
下面请看一个例子
class Father
{
static void Main(string[] args)
{
Console.WriteLine("创建父类对象");
Father father = new Father();
Console.WriteLine("父类调用Hello方法");
father.Hello();
Console.WriteLine("-------------------------------------------------");
Console.WriteLine("创建子类对象,字类调用Hello方法");
Child p = new Child();
p.Hello();
Console.ReadKey();
}
public void Hello()
{
this.Fly();
Console.WriteLine("this代表的类型是"+this.GetType());
}
public virtual void Fly()
{
Console.WriteLine("父类结果:我要飞我要飞");
}
}
class Child : Father
{
public override void Fly()
{
Console.WriteLine("子类结果:你要飞哪儿去呀!宝贝");
}
}
执行结果:
还是回到我们的反射中来,Type类的成员有很多,比如:IsInstanface、IsArray、IsPrimitive、IsEnum:是否为接口、数组、原始类型、枚举等。
String Name得到类名(不包含命名空间);String FullName包含命名空间
BaseType得到父类的Type
构造函数
ConstructorInfo GetConstructor(Type[] types)//获取参数类型匹配的构造函数
ConstructorInfo[] GetConstructors()//获得所有的public构造函数,包括父类的
调用object Invoke(object[] parameters)可以调用构造函数
方法
MethodInfo GetMethod(string name, Type[] types)
MethodInfo[] GetMethods() //获得所有的public方法
调用object Invoke(object obj, object[] parameters)可以调用方法
属性
PropertyInfo GetProperty(string name) 获取某个属性
PropertyInfo[] GetProperties() 获取所有属性
PropertyInfo的主要成员: CanRead、 CanWrite是否可读写; GetValue、 SetValue读写值(第一个参数是要在哪个对象要调用)
class Program
{
static void Main(string[] args)
{
#region 创建反射的三种方式
//对象获取
//Person p1 = new Person();
//Type type = p1.GetType();
//Console.WriteLine(type);
//类名获取
//Type type = typeof(Person);
//Console.WriteLine(type);
//全类名获取
//Type type = Type.GetType("反射.Person");
//object obj = Activator.CreateInstance(type);
//Type tpye2 = obj.GetType();
//Console.WriteLine(type);
#endregion
#region Type类的一些成员
//Type obj = typeof(Person);
//Console.WriteLine("obj的名字:" + obj.Name);
//Console.WriteLine("obj的完全名字(包括命名空间):" + obj.FullName);
//Console.WriteLine("obj的父类:" + obj.BaseType);
//Console.WriteLine("是不是公共的:" + obj.IsPublic);
//Console.WriteLine("获取唯一的GUID符号:" + obj.GUID);
#endregion
#region 反射中的构造函数
//Type t = typeof(Person);
//ConstructorInfo csStr = t.GetConstructor(new Type[] { typeof(string) });
//ConstructorInfo csInt = t.GetConstructor(new Type[] { typeof(int) });
//ConstructorInfo csMul = t.GetConstructor(new Type[] { typeof(string), typeof(int) });
//Console.WriteLine("输出有一个stirng参数类型的构造函数" + csStr);
//Console.WriteLine("输出有一个int参数类型的构造函数" + csInt);
//Console.WriteLine("输出有两个参数类型(int、string)的构造函数" + csMul);
//Console.WriteLine("-----------------------------------------");
//Console.WriteLine("获取所有公共构造函数信息");
//ConstructorInfo[] csInfo = t.GetConstructors();//获取所有公共构造函数
//foreach (var item in csInfo)
//{
// Console.WriteLine(item);
//}
//Console.WriteLine("------------------------------------------");
//Console.WriteLine("获取到私有的信息");
//ConstructorInfo[] csDefInfo = t.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);//包括公共、私有和实例
//foreach (var item in csDefInfo)
//{
// Console.WriteLine(item);
//}
//Console.WriteLine("------------------------------------------");
//Console.WriteLine("利用构造函数给Name赋值");
//object obj = csStr.Invoke(new object[] { "你好" });
//Console.WriteLine("执行完成以后的Name值:"+((Person)obj).Name);
#endregion
#region 反射中的方法
//Type t = typeof(Person);
//MethodInfo[] methods = t.GetMethods();
//Console.WriteLine("----------------------------------------");
//Console.WriteLine("获取Person类所有的方法和继承至父类的方法(都是Public的方法)");
//foreach (var item in methods)
//{
// Console.WriteLine(item);
//}
//Console.WriteLine("----------------------------------------");
//Console.WriteLine("查询指定的方法");
//MethodInfo flyMethod = t.GetMethod("Fly");
//if (flyMethod is null)
//{
// Console.WriteLine("Person中没有指定的方法");
//}
//else
//{
// Console.WriteLine("方法找到" + "返回值" + flyMethod.ReturnType + "方法为" + flyMethod);
//}
//object obj = Activator.CreateInstance(t);
//Console.WriteLine("----------------------------------------");
//Console.WriteLine("调用指定的方法");
//flyMethod.Invoke(obj, new string[] { });
//Console.WriteLine("----------------------------------------");
//Console.WriteLine("遍历所有方法");
//foreach (var item in methods)
//{
// if (item.IsStatic)
// {
// item.Invoke(null, new string[] { });
// }
// else if (item.Name.Equals("F1"))
// {
// item.Invoke(obj, new string[] { "账单!" });
// }
// else
// {
// Console.WriteLine("方法" + item.Name + "不是我们将要执行的方法!!!");
// Console.WriteLine();
// }
//}
#endregion
Type t = typeof(Person);
PropertyInfo[] properties = t.GetProperties();
foreach (var property in properties)
{
if (property.CanRead && property.CanWrite)
{
Console.WriteLine(property.Name + "能够读能够写");
}
else if (property.CanRead)
{
Console.WriteLine(property.Name + "能够读");
}
else if (property.CanWrite)
{
Console.WriteLine(property.Name + "能够写");
}
Console.WriteLine("----------------------------------------");
Console.WriteLine(property);
}
Console.WriteLine("----------------------------------------");
Console.WriteLine("获取指定的属性值");
object obj = Activator.CreateInstance(t);
PropertyInfo propertyInfo = t.GetProperty("Name");
propertyInfo.SetValue(obj, "Windows");
object name = propertyInfo.GetValue(obj);
Console.WriteLine("修改后的指定值为" + name);
Console.WriteLine("----------------------------------------");
Console.WriteLine("获取私有字段");
FieldInfo []fieldInfo = t.GetFields(BindingFlags.NonPublic|BindingFlags.Instance);
foreach (var item in fieldInfo)
{
Console.WriteLine(item.Name);
}
Console.ReadKey();
}
}
public class Person : Father
{
public int Age { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
public string Weight { get; }
private double height;
public double Height
{
set => this.height = value;
}
public Person()
{
}
private Person(int age)
{
this.Age = age;
}
public Person(int age, string name)
{
this.Age = age;
this.Name = name;
}
public Person(int age, string name, string sex)
{
this.Age = age;
this.Name = name;
this.Sex = sex;
}
public Person(string name)
{
this.Name = name;
Console.WriteLine("调用了我了!!!");
}
public Person(string name, string sex)
{
this.Name = name;
this.Sex = sex;
}
public void SayHello()
{
Console.WriteLine("你好呀");
}
public string F1(string name)
{
Console.WriteLine("f1方法");
return name;
}
public int F2()
{
Console.WriteLine("f2方法");
return this.Age;
}
public static string F3()
{
Console.WriteLine("f3方法,静态");
return "你好";
}
}
public class Father
{
//public int Age { get; set; }
//public string Name { get; set; }
//public string Sex { get; set; }
//public double Height { get; set; }
//public Father(int age, string name, string sex, double height)
//{
// this.Age = age;
// this.Name = name;
// this.Sex = sex;
// this.Height = height;
//}
//public Father(int age)
//{
// this.Age = age;
//}
//public Father(string name)
//{
// this.Name = name;
//}
//public Father()
//{
//}
public void Fly()
{
Console.WriteLine("起飞起飞!!!");
}
}