使用反射(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. 上传图片JS插件Plupload

    Plupload有以下功能和特点: 1.拥有多种上传方式:HTML5.flash.silverlight以及传统的<input type=”file” />.Plupload会自动侦测当前 ...

  2. Properties类、序列化流与反序列化流、打印流、commons-IO

    Properties类 特点: 1.Hashtable的子类,map集合中的方法都可以用: 2.该集合没有泛型,键值都是字符串: 3.是一个可以持久化的属性集,键值可以存到集合中,也可存到持久化的设备 ...

  3. hdu 1541

    因为y的输入是从小到大,所以不用考虑y坐标的问题 只考虑x坐标就行 还有个小细节就是0<=x,y,<=32000  x和y取0的时候树状数组处理不到 x++就行了 #include < ...

  4. unigui作中间件使用

    unigui作中间件使用 可返回string或者tstream数据. 如果返回JSON字符,则UNIGUI就是REST 中间件. procedure TUniServerModule.UniGUISe ...

  5. 分形之龙形曲线(Dragon Curve)

    龙形曲线(Dragon Curve)又叫分形龙,是一种自相似碎形曲线的统称,因形似龙的蜿蜒盘曲而得名. 一种简单的生成分形龙的方式是:拿着一条细长的纸带,把它朝下的一头拿上来,与上面的一头并到一起.用 ...

  6. 关于2011年meng-meng组产品《豆酱》的Review

    这个组是一个做手机应用的组,比较有特色. 经过我们的一致讨论,得出我们组对前辈的有关选题.团队.产品等几个方面的看法,以及我们的感想. 选题的特点: 这个选题对于一个短期项目来说是很合适的,经过较为详 ...

  7. Asp .Net core 2 学习笔记(1) —— Starup

    这个系列的初衷是便于自己总结与回顾,把笔记本上面的东西转移到这里,态度不由得谨慎许多,下面是我参考的资源: ASP.NET Core 中文文档目录 官方文档 记在这里的东西我会不断的完善丰满,对于文章 ...

  8. AJPFX:外汇的杠杆保证金是什么

    外汇杠杆和保证金两者有着密切的关系.杠杆越大,交易时所用的保证金就越少. 杠杆即为保证金可以缩小的倍数.例如在没有杠杆的情况下,做一手即10万的欧元兑美元货币对合约(现在价格是1.05821),您所需 ...

  9. XSS 跨站脚本攻击 的防御解决方案

    虽然说在某些特殊情况下依然可能会产生XSS,但是如果严格按照此解决方案则能避免大部分XSS攻击. 原则:宁死也不让数据变成可执行的代码,不信任任何用户的数据,严格区数据和代码. XSS的演示 Exam ...

  10. Java并发编程总结3——AQS、ReentrantLock、ReentrantReadWriteLock

    本文内容主要总结自<Java并发编程的艺术>第5章——Java中的锁. 一.AQS AbstractQueuedSynchronizer(简称AQS),队列同步器,是用来构建锁或者其他同步 ...