使用反射(Reflection)使得程序在运行过程中可以动态的获取对象或类型的类型信息,然后调用该类型的方法和构造函数,或访问和修改该类型的字段和属性;可以通过晚期绑定技术动态的创建类型的实例;可以获取程序集中的所有类型信息;可以在动态构建新类型;还可以检索元素所添加的特性;
  ※反射相关的类基本都位于命名空间System.Reflection中;
  ※动态构建新类型的类位于命名空间System.Reflection.Emit中;

  一、访问或修改类型的实例、静态字段:

public class MyClass
{
public int myField;
public static int myStaticField;
} //使用方式:
//访问或修改类型的实例字段myField
MyClass myObj = new MyClass() { myField = }; //创建实例
Type myType = typeof(MyClass); //获取类型,或myObj.GetType()
FieldInfo fieldInfo = myType.GetField("myField"); //获取类型中指定的字段信息
Console.WriteLine((int)fieldInfo.GetValue(myObj)); //1,获取实例字段的值
fieldInfo.SetValue(myObj, ); //给实例字段赋值
//访问或修改类型的静态字段myStaticField
FieldInfo staticFieldInfo = myType.GetField("myStaticField"); //获取类型中指定的字段信息
Console.WriteLine(staticFieldInfo.GetValue(null)); //0,获取静态字段的值
staticFieldInfo.SetValue(null, ); //给静态字段赋值

  ※与直接赋值相比,使用反射赋值用时约长75倍,使用以下代码多次测试:

public class MyClass
{
public int myField;
} class Program
{
static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
MyClass myObj = new MyClass() { myField = };
Type myType = typeof(MyClass);
FieldInfo fieldInfo = myType.GetField("myField"); stopwatch.Start();
for (int i = ; i < 10_000_000; i++)
{
fieldInfo.SetValue(myObj, );
}
stopwatch.Stop();
Console.WriteLine($"使用反射赋值1千万次耗时:{stopwatch.ElapsedMilliseconds}"); stopwatch.Reset();
stopwatch.Start();
for (int i = ; i < 10_000_000; i++)
{
myObj.myField = ;
}
stopwatch.Stop();
Console.WriteLine($"直接赋值1千万次耗时:{stopwatch.ElapsedMilliseconds}");
Console.Read();
}
}

  二、访问或修改类型的实例、静态属性:

public class MyClass
{
public int MyProperty { get; set; }
public static int MyStaticProperty { get; set; }
}
//使用方式:
//访问或修改类型的实例属性MyProperty
MyClass myObj = new MyClass() { MyProperty = }; //创建实例
Type myType = typeof(MyClass); //获取类型,或myObj.GetType()
PropertyInfo propertyInfo = myType.GetProperty("MyProperty"); //获取类型中指定的属性信息
Console.WriteLine((int)propertyInfo.GetValue(myObj, null)); //1,获取实例属性的值
propertyInfo.SetValue(myObj, , null); //给实例属性赋值 //访问或修改类型的静态属性MyStaticProperty
PropertyInfo staticPropertyInfo = myType.GetProperty("MyStaticProperty"); //获取类型中指定的属性信息
Console.WriteLine(staticPropertyInfo.GetValue(null, null)); //0,获取静态属性的值
staticPropertyInfo.SetValue(null, ); //给静态属性赋值

  ※在使用反射给属性赋值时,如果该属性不具有set访问器,则会抛出异常ArgumentException;

  三、调用类型的方法:

public class MyClass
{
  public void MyFunc(int num)
  {
    Console.WriteLine("MyFunc(int num) execute, the parameter is: " + num);
  }
  public static void MyStaticFunc(int num)
  {
  Console.WriteLine("MyStaticFunc(int num) execute, the parameter is: " + num);
  }
}
//使用方式:
//调用类型的实例方法MyFunc
MyClass myObj = new MyClass(); //创建实例
Type myType = typeof(MyClass); //获取类型,或myObj.GetType()
MethodInfo methodInfo = myType.GetMethod("MyFunc"); //获取类型中指定的方法信息
methodInfo.Invoke(myObj, new object[] { }); //调用实例方法,并传入参数,无参传null
//MyFunc(int num) execute, the parameter is: 10 //调用类型的实例方法MyStaticFunc
MethodInfo staticMethodInfo = myType.GetMethod("MyStaticFunc"); //获取类型中指定的方法信息
staticMethodInfo.Invoke(null, new object[] { }); //调用静态方法,并传入参数,无参传null
//MyStaticFunc(int num) execute, the parameter is: 20

  四、调用类型的构造函数同时创建实例:

public class MyClass
{
public MyClass()
{
Console.WriteLine("MyClass() execute.");
}
public MyClass(int num)
{
Console.WriteLine("MyClass(int num) execute, the parameter is: " + num);
}
}
//使用方式:
//调用无参的构造函数
Type myType = typeof(MyClass); //获取类型,或myObj.GetType()
ConstructorInfo constructorInfo = myType.GetConstructor(new Type[] { }); //获取类型中指定的构造函数信息,传入该构造函数的参数列表的类型数组,无参传空数组
MyClass myObj = constructorInfo.Invoke(null) as MyClass; //通过调用构造函数创建实例,无参传null
//MyClass() execute. //调用带参数的构造函数
constructorInfo = myType.GetConstructor(new Type[] { typeof(int) }); //获取类型中指定的构造函数信息,传入该构造函数的参数列表的类型数组
myObj = constructorInfo.Invoke(new object[] { }) as MyClass; //通过调用构造函数创建实例,并传入参数
//MyClass(int num) execute, the parameter is: 20

  ※也可以使用Type类中的实例方法InvokeMember()来调用指定成员;

  五、使用反射查找特性:

  1.如果元素使用了特性,在没有检索并对其进行操作前该特性没有任何价值,可以使用反射在程序运行过程中获取元素添加的特性然后对其进行操作,使用特性基类Attribute中的静态方法GetCustomAttributes(MemberInfo element)或命名空间System.Reflection中的扩展方法GetCustomAttributes(this MemberInfo element)来获取类型或成员的所有特性信息:

Attribute[] attributes = Attribute.GetCustomAttributes(typeof(MyClass));
//IEnumerable<Attribute> attributes = typeof(MyClass).GetCustomAttributes();
foreach (var item in attributes)
{
  if (item is MyselfAttribute)
  {
    MyselfAttribute attribute = item as MyselfAttribute;
    Console.WriteLine(attribute .ClassName + " " + attribute .Author); //MyClass Me
  }
}

  2.这两个方法都有对应的重载方法,可以传入要检索的指定特性的类型,这样即可得到元素中所有指定类型的特性信息:

Attribute[] attributes = Attribute.GetCustomAttributes(typeof(MyClass), typeof(MyselfAttribute));
//IEnumerable<Attribute> attributes = typeof(MyClass).GetCustomAttributes(typeof(MyselfAttribute));
foreach (var item in attributes)
{
  MyselfAttribute attribute = item as MyselfAttribute;
  Console.WriteLine(attribute.ClassName + " " + attribute.Author); //MyClass Me
}

  ※如果未找到任何特性或指定类型的特性,这些方法会返回一个空数组;

  3.也可以使用基类Attribute中的静态方法GetCustomAttribute(MemberInfo element, Type attributeType)或命名空间System.Reflection中的扩展方法GetCustomAttribute(this MemberInfo element, Type attributeType)来获取类型或成员的指定特性信息;
  ※如果未找到指定类型的特性,会返回null;
  ※在检索的元素中存在多个相同的指定类型的特性时,会抛出异常Reflection.AmbiguousMatchException;

  类型信息、晚期绑定、动态创建类型等会在下一篇中介绍。


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的认可是我写作的最大动力!

作者:Minotauros
出处:https://www.cnblogs.com/minotauros/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

详解C#特性和反射(二)的更多相关文章

  1. 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码

    详解C#泛型(二)   一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...

  2. EF+LINQ事物处理 C# 使用NLog记录日志入门操作 ASP.NET MVC多语言 仿微软网站效果(转) 详解C#特性和反射(一) c# API接受图片文件以Base64格式上传图片 .NET读取json数据并绑定到对象

    EF+LINQ事物处理   在使用EF的情况下,怎么进行事务的处理,来减少数据操作时的失误,比如重复插入数据等等这些问题,这都是经常会遇到的一些问题 但是如果是我有多个站点,然后存在同类型的角色去操作 ...

  3. 详解C#特性和反射(四)

    本篇内容是特性和反射的最后一篇内容,前面三篇文章: 详解C#特性和反射(一) 详解C#特性和反射(二) 详解C#特性和反射(三) 一.晚期绑定(Late Binding)是一种在编译时不知道类型及其成 ...

  4. 详解C#特性和反射(一)

    使用特性(Attribute)可以将描述程序集的信息和描述程序集中任何类型和成员的信息添加到程序集的元数据和IL代码中,程序可以在运行时通过反射获取到这些信息: 一.通过直接或间接的继承自抽象类Sys ...

  5. 详解C#特性和反射(三)

    类型信息(Type Information)用来表示类型声明的信息,通过抽象基类System.Type的实例存储这些信息,当使用反射时,CLR获取指定类型的Type对象,通过这个对象即可访问该类型的任 ...

  6. 【转】详解C#中的反射

    原帖链接点这里:详解C#中的反射   反射(Reflection) 2008年01月02日 星期三 11:21 两个现实中的例子: 1.B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到你内 ...

  7. 详解Java8特性之新的日期时间 API

    详解Java8特性之新的日期时间 API http://blog.csdn.net/timheath/article/details/71326329 Java8中时间日期库的20个常用使用示例 ht ...

  8. Git使用总结 Asp.net生命周期与Http协议 托管代码与非托管代码的区别 通过IEnumerable接口遍历数据 依赖注入与控制反转 C#多线程——优先级 AutoFac容器初步 C#特性详解 C#特性详解 WPF 可触摸移动的ScrollViewer控件 .NET(C#)能开发出什么样的APP?盘点那些通过Smobiler开发的移动应用

    一,原理 首先,我们要明白Git是什么,它是一个管理工具或软件,用来管理什么的呢?当然是在软件开发过程中管理软件或者文件的不同版本的工具,一些作家也可以用这个管理自己创作的文本文件,由Linus开发的 ...

  9. WebApi接口传参不再困惑(4):传参详解 一、get请求 二、post请求 三、put请求 四、delete请求 五、总结

    前言:还记得刚使用WebApi那会儿,被它的传参机制折腾了好久,查阅了半天资料.如今,使用WebApi也有段时间了,今天就记录下API接口传参的一些方式方法,算是一个笔记,也希望能帮初学者少走弯路.本 ...

随机推荐

  1. C#-.Net Framework和.Net Compact Framework-摘

    .Net Compact Framework 一种独立于硬件的环境,用于在资源受限制的计算设备上运行程序.它继承了公共语言运行时的完整 .NET Framework 结构,支持 .NET Framew ...

  2. git使用教程(初次配置+错误提示)

    初次使用配置目录:https://blog.csdn.net/Esc_Tab_End/article/details/84144063 error: RPC failed; curl 56 OpenS ...

  3. MapGIS10.3新功能

    智能的GIS 支持开放的数据集.数据库.等等 T-C-V 软件结构是继局部网软件的 C/S 结构,互联网软件的 B/S 结构发展起来的适合云 计算.云服务的新一代软件三层结构,分别为终端应用层(T 层 ...

  4. mybatis的update操作的几种动态更新

    mybatis是我们开发者常用的dao框架,亿轻巧灵活为特征,在crud操作中,动态更新是常用的操作.我搜集了两种动态更新的sql写法,以备日后备用! 方法1: update loan_product ...

  5. _ZSkill_快捷键_Xcode快捷键

    Xcode 快捷键使用 Command 用来导航,控制导航区域 Alt 控制右边的部分. 如Assistant Editor ,utility editor. Control 编辑区域上的jump b ...

  6. Android 响应menu,back键,点击外部消失

    点击外部消失,只需要设置popupWindow.setBackgroundDrawable(new PaintDrawable()); 设置 popupWindow.setFocusable(true ...

  7. Android-Java静态代码块&局部代码块

    静态代码块: 静态代码块什么时候执行,是由当前类被加载进内存的时候,什么时候当前类被加载进内存? 答:例如 描述好了Student对象,当 new Student(); 的时候,第一步:是把Stude ...

  8. hdu 1.3.2 Moving Tables

    这道题比较简单,就是用数组存取其路径.如101和102是对门,其过道号可以记为51.  1和2之间的为1. 今早突然收到操作系统停课的通知,哈哈 回来就做一下水题,开心 #include<cst ...

  9. 用 select 语句实现递归的方法

    with Test_Recursion(Id,ParentId)AS(select Id,ParentId  from [V_KPI_DetailsActivities] where ParentId ...

  10. java的环境变量

    Java学习第一步——JDK安装及Java环境变量配置  2014-05-30 9:09  Java SE  阿超  9226 views Java作为当下很主流的编程语言,学习Java的朋友也越来越 ...