【C#】反射基础

1.基础

反射性能不高。
反射:运行时获取加载到内存中的程序集的元信息。
反射的作用:访问object实例的成员(fields,properties,methods)

(1)对装箱操作的object实例获取成员

Type GetType()——获取类型
GetFields()——获取所有公开字段
FieldInfo GetField(string filedName)——获取指定字段
GetProperties()——获取所有公开属性
PropertyInfo GetProperty(string propertyName)——获取属性名
MethodInfo[] GetMethods()——获取所有公开方法
MethodInfo GetMethod(string methodName)——获取指定方法

Type常用

Namespace
Name
FullName

PropertyInfo常用

Name
FullName
Method

MethodInfo常用

Invoke(obj, new object[] 参数列表)——调用方法

namespace Model
{
	class Person
{
	private int age;
	public int Age{get=>age;set=>age=value;}
	private string name;
	public int Name{get=>name;set=>name=value;}
	
	public Person(){}
	
	public Person(int age, string name)
	{
		this.age=age;
		this.name=name;
	}
	
	public string SayHi(string name)
	{
		return "hello " + name;
	}
}

}
object obj = new Person();

//获取object原本的类型——GetType()
Type typeobj = obj.GetType();	

//Type常用属性
Console.WriteLine(typeobj.Namespace);	//命名空间
Console.WriteLine(typeobj.Name);	//类名
Console.WriteLine(typeobj.FullName);	//完全限定名


//获取所有公开字段——type.GetFields()
foreach(var field in typeobj.GetFields())
{
	Console.WriteLine(field.Name);	//字段名
	Console.WriteLine(field.FullName);	//字段完全限定名
	//注意:需要将object实例传入
	field.SetValue(obj, new object[] param);	//给字段赋值。
	field.GetValue(obj);	//获取字段值
}

//获取指定字段——type.GetField(string fieldName)
var field = type.GetField("age");	//传入字段名
field.SetValue(obj, new object[]{30});
Console.WriteLine(field.GetValue(obj).toString());

//获取所有公开属性——type.GetProperties()
foreach(var property in typeobj.GetProperties())
{
	Console.WriteLine(property.Name);	
	Console.WriteLine(property.FullName);	
	
	field.SetValue(obj, new object[] param);	
	field.GetValue(obj);	
}

//获取指定属性
var property = type.GetProperty("age");	//传入字段名
property.SetValue(obj, new object[]{30});
Console.WriteLine(property.GetValue(obj).toString());

//获取所有公开方法——type.GetMethods()
//会获取构造、get/set访问器(属性)、成员方法
foreach(var method in type.GetMethods())
{
	Console.WriteLine(method.Name);	//方法名
}

//获取指定方法——type.GetMehod(string methodName)
//第二个参数是传入方法的参数列表。
//Invoke调用方法,返回值是object。
object ret = objtype.GetMethod("SayHi").Invoke(obj, new object[]{"wk"});	
Console.WriteLine(ret.toString());

(2)对通过程序集获取的类型获取成员

Assembly常用(using Reflection)

Assembly Assembly.LoadFile(string path)——加载程序集文件的内容。Path必须是绝对路径。
Assembly Assembly.GetExecutingAssembly——获取当前正在执行的程序集
Type GetTypes()——获取程序集里所有声明的类型。通过Type的IsClass等属性过滤出想要的类型。

读取dll文件,获取其中的类型:

string libPath = Environment.CurrentDirectory + @"\libs\xxx.dll";
Assembly ass = Assembly.LoadFile(libPath);

//遍历程序集中的类型
foreach(var type in ass.GetTypes())
{
	Console.WriteLine(type.Name);
	Console.WriteLine(type.FullName);
	Console.WriteLine(type.IsClass);	//判断是不是类
	Console.WriteLine(type.IsAbstract);	//抽象
	Console.WriteLine(type.IsEnum);		//枚举
	Console.WriteLine(type.IsInterface);	//接口
}

现在获取了程序集中的类型,比如类。如果,能够创建一个实例,就可以通过(1)中的GetFeidls()、GetProperties()、GetMethods()等方法获取类型的成员。
怎么创建实例对象呢:object ass.GetInstance(string typeFullName)

通过创建实例对象获取成员:

//通过Type的Is系列属性过滤出想要的类型
Type personType = ass.GetTypes().First(m => m.IsClass && !m.IsAbstract);	//取出ass程序集中的非抽象类

object person = ass.GetInstance(personType.FullName);
person.GetProperty("Age").SetValue(person, "30");
person.GetProperty("Name").SetValue(person, "wk");
person.GetMethod("SayHi")?.Invoke(person, new object[]{"wk"});

(3)Assembly.CreateInstance和Activator.CreateInstance的区别

2.反射实现更新dll

更新程序通过对比服务器上记录的当前最新版本号和当前用户的客户端版本号,若非最新版,可连接服务器下载最新dll替换到客户端。
客户端代码通过反射加载dll,而不是通过VS引用加载。在不更改客户端代码的情况下,替换dll更新功能。

/*
*客户端通过反射获取dll中内容进行调用
*/
Assembly ass = Assembly.LoadFile(Environment.CurrentDirectory + @"\libs\xxx.dll");

object person = ass.GetInstance("Model.Person");
person.GetMethod("SayHi")?.Invoke(person, new object[]{"wk"});
/*
*新dll
*/
namespace Model
{
	class Person
{
	private int age;
	public int Age{get=>age;set=>age=value;}
	private string name;
	public int Name{get=>name;set=>name=value;}
	
	public Person(){}
	
	public Person(int age, string name)
	{
		this.age=age;
		this.name=name;
	}
	
	public string SayHi(string name)
	{
		return "hello gamePlayer:" + name;	//添加内容
	}
}

}
/*
*更新程序
*/
File.Delete("\libs\xxx.dll");
File.Copy("\temp\xxx.dll", "\libs\xxx.dll");
MessageBox.Show("更新成功");

3.插件

4.与Attribute特性标签

Attribute:为类、接口、方法等添加额外声明信息的标签。
反射可获取加载到内存中的程序集的元信息,也包括Attribute。
作用:通过反射+标签,自动按照标签分类使用类型。
标签是类,继承自Attribute类。

Attribute.GetCustomAttributes
Enumerable.Any

class HeroAttribute:Attribute{}

[HeroAttribute]
class Hero1
{
	[SkillAttribute]
	public void skill1(){}
}
List<Type> heroTypes;
//获取所有标签为HeroAttribute的类
heroTypes=Assembly.GetExcutingAssembly().GetTypes().Where(t=>t.GetCustomAttributes(typeof(HeroAttribute), false).Any()).ToList();	

var heroObj = Activator.CreateInstance(heroTypes[0]);	

//获取类型heroTypes[0]所有标签为SkillAttribute的方法
var skillMethods = heroTypes[0].GetMethods().Where(t=>t.GetCustomAttributes(typeof(SkillAttribute), false).Any()).ToList();	
posted @ 2023-07-04 18:28  neon233  阅读(16)  评论(0编辑  收藏  举报