反射用于在程序运行过程中,获取类里面的信息或发现程序集并运行的一个过程。通过反射可以获得.dll和.exe后缀的程序集里面的信息。使用反射可以看到一个程序集内部的类,接口,字段,属性,方法,特性等信息。
先定义一个类
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceConsoleapplication2
{
[Serializable]classPoster
{PRivateintcount;publicstringOwnerName {get;set; }publicstringTitle {get;set; }publicstringContent {get;set; }publicvoidmakePoster(stringtitile,stringcontent) {
Title=titile;
Content=content;
}publicstringgetPoster() {return"Title:"+Title+"Content:"+Content +"postby"+OwnerName;
}publicstringgetPoster(strings) {returns;
}
}
}
1.获得Type对象通过字符串如:Type t1 = Type.GetType("ConsoleApplication2.Poster");
具体的类:Type t2 = typeof(ConsoleApplication2.Poster);
通过实例:Poster p = new Poster();
Type t3 = p.GetType();
2.通过System.Reflection.Assembly类通过Assembly可以动态加载程序集,并查看程序集的内部信息,其中最常用的就是Load()这个方法。Assembly assembly = Assembly.Load("MyAssembly");
注意在Assembly里面的加载程序集有3个方法,分别是Load、LoadFrom和LoadFile。这3个方法有什么异同呢?
1、如果你引用了命名空间,那么就直接Load()方法,参数里面写上命名空间+类名就可以加载了。
2、如果仅仅知道一个dll文件的那么就要用LoadFrom()方法了,参数里面直接填写完整的路径。
LoadFrom 方法具有以下缺点。请考虑改用 Load。
-如果已加载一个具有相同标识的程序集,则即使指定了不同的路径,LoadFrom 仍返回已加载的程序集。
-如果用 LoadFrom 加载一个程序集,随后加载上下文中的一个程序集尝试加载具有相同显示名称的程序集,则加载尝试将失败。对程序集进行反序列化时,可能发生这种情况。
总结: LoadFrom只能用于加载不同标识的程序集, 也就是唯一的程序集, 不能用于加载标识相同但路径不同的程序集。
3、LoadFile (加载指定路径上的程序集文件的内容。)
这个方法是从指定的文件来加载程序集,它是调用外部的API实现的加载方式,和上面Load,LoadFrom方法的不同之处是这个方法不会加载此程序集引用的其他程序集,也就是不会加载程序的依赖项。而同时也是不能加载相同标识的程序集的。
利用Assembly的object CreateInstance(string)方法可以反射创建一个对象,参数0为类名。
3.System.Reflection常用类类型
作用
Assembly
通过此类可以加载操纵一个程序集,并获取程序集内部信息
EventInfo
该类保存给定的事件信息
FieldInfo
该类保存给定的字段信息
MethodInfo
该类保存给定的方法信息
MemberInfo
该类是一个基类,它定义了EventInfo、FieldInfo、MethodInfo、PropertyInfo的多个公用行为
Module
该类可以使你能访问多个程序集中的给定模块
ParameterInfo
该类保存给定的参数信息
PropertyInfo
该类保存给定的属性信息
4.反射方法参看3小结表列表中的MethodInfo,在调用方法时候注意是否重载,下面代码表示了在相同方法名称,不同签名的情况下方法的获取,一般来说如果只有一个方法只需使用
GetMethod(“方法的名称”)
privatestaticvoidrec()
{
Poster pp=newPoster();
Type p= Type.GetType("ConsoleApplication2.Poster");
Console.WriteLine(p.ToString());
Type p2=typeof(ConsoleApplication2.Poster);
Console.WriteLine(p2.ToString());
Console.WriteLine(pp.GetType().ToString());stringpath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase +"ConsoleApplication2.exe";
Assembly ss=Assembly.LoadFrom(path);
Console.WriteLine(ss.GetType("ConsoleApplication2.Poster").ToString() +"4");
Module mod= ss.GetModules()[0];
Console.WriteLine(mod.GetType("ConsoleApplication2.Poster").ToString() +"5");//以上是加载的各种方法MethodInfo[] methodList=p.GetMethods();foreach(MethodInfo infoinmethodList)
{
Console.WriteLine(info.ToString());//方法列表}objectobject_p = Activator.CreateInstance(p);//实例化一个对象Type[] types =newType[1];
types[0] =typeof(string);
MethodInfo meth= p.GetMethod("getPoster", types);//获取getPoser(string s)方法object[] ob =newobject[1];//传入参数ob[0] ="good dog";
Console.WriteLine(meth.Invoke(object_p, ob));//调用该方法Type[] types2=newType[0];
MethodInfo meth2= p.GetMethod("getPoster",types2);//获取getPoster()方法Console.WriteLine(meth2.Invoke(object_p,null));
}
结果为如下
这里可以看到属性的生成方法。反射得到方法的列表默认是public的方法
5.反射属性反射属性的获得是用列表中的PropertyInfo,和方法的书写格式基本一样,一个GetProperties针对枚举,一个是GetProperty针对个例,通过SetValue和GetValue进行赋值和取值
privatestaticvoidrec2() {
Type p= Type.GetType("ConsoleApplication2.Poster");//获得反射对象Console.WriteLine(p.ToString());
PropertyInfo[] p_info= p.GetProperties();//获得反射的所有公开属性foreach(PropertyInfo p_ininp_info) {
Console.WriteLine(p_in.ToString());
}objectp_r = Activator.CreateInstance(p);//创建一个实例PropertyInfo ptile = p.GetProperty("Title");//获得Title属性ptile.SetValue(p_r,"这个是主题");//设置属性值Console.WriteLine( ptile.GetValue(p_r).ToString());//获得属性值}
输出结果为
6.属性和方法的综合用例为属性复制,取值,通过方法进行处理
privatestaticvoidATest() {
Type poster=typeof(ConsoleApplication2.Poster);objectnewposter =Activator.CreateInstance(poster);
PropertyInfo p_owner= poster.GetProperty("OwnerName");
p_owner.SetValue(newposter,"Keith");//为用户赋值MethodInfo p_make = poster.GetMethod("makePoster");//获得makePoster方法object[] para =newobject[2];
para[0] ="天气";
para[1] ="北京的天气最近真的很差啊";
p_make.Invoke(newposter, para);//传入参数Type[] types =newType[0];
MethodInfo p_getposter= poster.GetMethod("getPoster", types);//获得getPoster方法注意和获得makePoster不同Console.WriteLine(p_getposter.Invoke(newposter,null));//输出}
输出结果
privatestaticvoidsetPosterRec() {
Dictionary<string,string> oneposter=newDictionary<string,string>();
oneposter.Add("OwnerName","Keith");
oneposter.Add("Title","回复Rita");
oneposter.Add("Content","确实不怎么样这天气");
Type poster=typeof(ConsoleApplication2.Poster);objectnewposter =Activator.CreateInstance(poster);
PropertyInfo[] pinfo=poster.GetProperties();foreach(PropertyInfo pinpinfo) {if(oneposter.ContainsKey(p.Name)) {
p.SetValue(newposter, Convert.ChangeType(oneposter[p.Name], p.PropertyType));
}
}
Poster thisp= newposterasPoster;
Console.WriteLine(thisp.getPoster());
}
7.模拟属性值批量赋值
privatestaticvoidsetPosterRec() {
Dictionary<string,string> oneposter=newDictionary<string,string>();
oneposter.Add("OwnerName","Keith");
oneposter.Add("Title","回复Rita");
oneposter.Add("Content","确实不怎么样这天气");//假设数据来自xmlType poster =typeof(ConsoleApplication2.Poster);objectnewposter =Activator.CreateInstance(poster);
PropertyInfo[] pinfo= poster.GetProperties();//获得属性列表foreach(PropertyInfo pinpinfo) {if(oneposter.ContainsKey(p.Name)) {//枚举属性列表根据属性的名字和字典key值相同的赋值p.SetValue(newposter, Convert.ChangeType(oneposter[p.Name], p.PropertyType));//Convert.ChangeType(oneposter[p.Name], p.PropertyType),根据反射的对象类型进行赋值}
}
Poster thisp= newposterasPoster;
Console.WriteLine(thisp.getPoster());
}
这段代码有一个关键的地方就是Convert.ChangeType(oneposter[p.Name], p.PropertyType) 这里将字典中value转换为类Poster中相同的类型,否则在赋值的时候会报错
输出结果
8.读取类中的字段和特性Poster中有一个私有字段Count,我们来把他变化一下输出,特性的输出用GetCustomAttribute
privatestaticvoidgetprivateRec() {
Type poster=typeof(ConsoleApplication2.Poster);objectnewposter =Activator.CreateInstance(poster);/*FieldInfo 读取类中的字段,第一个是字段名称,后面是枚举参数值,包括private和public*/FieldInfo file= poster.GetField("count",BindingFlags.NonPublic | BindingFlags.Instance |BindingFlags.Public);/*后面的和属性一样*/file.SetValue(newposter,200);
Console.WriteLine(file.GetValue(newposter));/*这里是输出特性*/object[] typeAttribute = poster.GetCustomAttributes(false);foreach(objectaintypeAttribute) {
Console.WriteLine(a.ToString());
}
}
输出结果