谈谈对C#中反射的一些理解和认识(上)
今天就平常用到的非常多的反射这个技术来做一个总结,当然关于反射需要讲解的东西实在是太多的内容,在一片文章中想要讲解清楚是非常难的,本篇博客也是就自己本人对这些内容学习后的一个总结,当然包括看书和自己写过的一些代码中抽取的一些示例,而且本文也仅限于此时对于这个知识点的理解,希望通过以后的逐步学习能够不断加深对这个知识点的理解。
首先来看看对于反射的基础知识点。
1 定义:首先看看MSDN怎样对它进行解释吧
反射提供了封装程序集、模块和类型的对象(Type 类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。
2 反射有什么作用?
A、将类型绑定到现有对象,或从现有对象中获取类型信息,这些信息包括(Assembly MemberInfo EventInfo FieldInfo MethodBase ConstructorInfo MethodInfo PropertyInfo 等等 )另外可以使用反射动态地创建类型的实例,
例如:
1、System.Activator 的CreateInstance方法。该方法返回新对象的引用。
2、System.Activator 的CreateInstanceFrom 与上一个方法类似,不过需要指定类型及其程序集
3、System.Appdomain 的方法:CreateInstance,CreateInstanceAndUnwrap,CreateInstranceFrom和CreateInstraceFromAndUnwrap
4、System.Type的InvokeMember 实例方法:这个方法返回一个与传入参数相符的构造函数,并构造该类型。
5、System.Reflection.Constructinfo 的Invoke实例方法
下面通过一段代码来了解这5种创建实例的方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using OptimizeReflection;
using System.Collections;
using System.Web; namespace TestOptimizeReflection
{
public class OrderInfo
{
public int OrderID { get; set; }
public DateTime OrderDate { get; set; }
public decimal SumMoney { get; set; }
public string Comment { get; set; }
public bool Finished { get; set; } public int Add(int a, int b)
{
return a + b;
}
} class Program
{
static void Main()
{
TestNewInstance();
} static void TestNewInstance()
{
//常规方法创建对象
OrderInfo testObj = new OrderInfo(); #region 常规反射创建
//利用反射来动态创建对象
Type instanceType = typeof(OrderInfo);
OrderInfo orderInfo = (OrderInfo)Activator.CreateInstance(instanceType);
#endregion #region Activator.CreateInstanceFrom 创建
//注意Assembly.GetEntryAssembly().CodeBase表示当前执行的exe所在的路径,instanceType.FullName表示当前OrderInfo的类型名称TestOptimizeReflection.OrderInfo
System.Runtime.Remoting.ObjectHandle oh= Activator.CreateInstanceFrom(Assembly.GetEntryAssembly().CodeBase, instanceType.FullName);
//返回被包装的对象
OrderInfo orderInfoEx = (OrderInfo)oh.Unwrap();
#endregion #region System.AppDomain.CurrentDomain实例创建对象
System.Runtime.Remoting.ObjectHandle ohEx = System.AppDomain.CurrentDomain.CreateInstance(Assembly.GetEntryAssembly().FullName, instanceType.FullName);
OrderInfo orderInfoExEx = (OrderInfo)ohEx.Unwrap();
//合并上面的两步
OrderInfo orderInfoExExEx = (OrderInfo)System.AppDomain.CurrentDomain.CreateInstanceAndUnwrap(Assembly.GetEntryAssembly().FullName, instanceType.FullName);
#endregion #region InvokeMember方法创建实例
OrderInfo invokeMemberOrderInfo = (OrderInfo)instanceType.InvokeMember(null, BindingFlags.Public| BindingFlags.Instance | BindingFlags.Static|BindingFlags.CreateInstance, System.Type.DefaultBinder, null, null);
#endregion #region 调用构造器创建
//调用无参数的默认构造函数
ConstructorInfo ci = instanceType.GetConstructor(new Type[] { });
OrderInfo ciOrderInfo = (OrderInfo)ci.Invoke(null);
#endregion
}
}
}
B、应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。
这个该怎样去理解呢?这个可以用插件系统中的同类思想去解释,在构建插件系统的时候,我们有时候需要主程序去动态地调用插件,可能应用程序只有在执行某一操作的时候才能够去调用相关的DLL,这个时候我们就可以通过反射这种方式来动态调用dll中分特定方法或者类型,这个也是经常使用到的。
C、反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。
D、反射能够调用一些私有方法和字段等。
这个需要重点去讲述,我们知道常规的实例方法由于受到作用域的影响,很多时候当方法设置为Private或者是其它的限制访问的关键字时就无能为力了,这个也是完全能够体现类的封装性,但是通过反射就能够完全绕开这些限制,下面举出一些对私有变量或字段、方法的一些访问方式,能够直接进行访问,这样还是非常方便的,具体请参考下面的代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks; namespace Dvap.Infrastructure.Utils
{
public static class ReflectionUtil
{
/// <summary>
/// 得到私有字段的值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
/// <param name="fieldname"></param>
/// <returns></returns>
public static T GetPrivateField<T>(this object instance, string fieldname)
{
BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic;
Type type = instance.GetType();
FieldInfo field = type.GetField(fieldname, flag);
return (T)field.GetValue(instance);
} /// <summary>
/// 设置私有成员的值
/// </summary>
/// <param name="instance"></param>
/// <param name="fieldname"></param>
/// <param name="value"></param>
public static void SetPrivateField(this object instance, string fieldname, object value)
{
BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic;
Type type = instance.GetType();
FieldInfo field = type.GetField(fieldname, flag);
field.SetValue(instance, value);
} /// <summary>
/// 得到私有属性的值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
/// <param name="propertyname"></param>
/// <returns></returns>
public static T GetPrivateProperty<T>(this object instance, string propertyname)
{
BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic;
Type type = instance.GetType();
PropertyInfo field = type.GetProperty(propertyname, flag);
return (T)field.GetValue(instance, null);
} /// <summary>
/// 设置私有属性的值
/// </summary>
/// <param name="instance"></param>
/// <param name="propertyname"></param>
/// <param name="value"></param>
public static void SetPrivateProperty(this object instance, string propertyname, object value)
{
BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic;
Type type = instance.GetType();
PropertyInfo field = type.GetProperty(propertyname, flag);
field.SetValue(instance, value, null);
} /// <summary>
/// 调用私有方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
/// <param name="name"></param>
/// <param name="param"></param>
/// <returns></returns>
public static T CallPrivateMethod<T>(this object instance, string name, params object[] param)
{
BindingFlags flag = BindingFlags.Instance | BindingFlags.NonPublic;
Type type = instance.GetType();
MethodInfo method = type.GetMethod(name, flag);
return (T)method.Invoke(instance, param);
}
}
}
E 还可以通过反射来获取属性或者类上的特性
有时候我们需要在类或者属性上面添加自定义的特性,并且通过反射能够获取到这些特性,那么这个时候我们就可以使用反射来达到目的了。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using OptimizeReflection;
using System.Collections;
using System.Web; namespace TestOptimizeReflection
{ /// <summary>
/// 自定义特性 属性或者类可用 支持继承
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, Inherited = true)]
public class EnitityMappingAttribute : Attribute
{
private string tableName;
/// <summary>
/// 实体实际对应的表名
/// </summary>
public string TableName
{
get { return tableName; }
set { tableName = value; }
} private string columnName;
/// <summary>
/// 中文列名
/// </summary>
public string ColumnName
{
get { return columnName; }
set { columnName = value; }
}
} /// <summary>
/// 会员 ,实际的表名叫MemberInfo,并不是和实体名一致
/// </summary>
[EnitityMapping(TableName = "MemberInfo")]
public class Member
{
private int id;
[EnitityMapping(ColumnName = "关键字")]
public int Id
{
get { return id; }
set { id = value; }
} private string userName;
[EnitityMapping(ColumnName = "会员注册名")]
public string UserName
{
get { return userName; }
set { userName = value; }
} private string realName;
[EnitityMapping(ColumnName = "会员真实名")]
public string RealName
{
get { return realName; }
set { realName = value; }
} private bool isActive;
/// <summary>
/// 是否活跃 没有附加自定义属性
/// </summary>
public bool IsActive
{
get { return isActive; }
set { isActive = value; }
}
} class Program
{
/// <summary>
/// 通过反射取自定义属性
/// </summary>
/// <typeparam name="T"></typeparam>
private static void DisplaySelfAttribute<T>() where T : class, new()
{
string tableName = string.Empty;
List<string> listColumnName = new List<string>();
Type objType = typeof(T);
//取属性上的自定义特性
foreach (PropertyInfo propInfo in objType.GetProperties())
{
object[] objAttrs = propInfo.GetCustomAttributes(typeof(EnitityMappingAttribute), true);
if (objAttrs.Length > 0)
{
EnitityMappingAttribute attr = objAttrs[0] as EnitityMappingAttribute;
if (attr != null)
{
listColumnName.Add(attr.ColumnName); //列名
}
}
} //取类上的自定义特性
object[] objs = objType.GetCustomAttributes(typeof(EnitityMappingAttribute), true);
foreach (object obj in objs)
{
EnitityMappingAttribute attr = obj as EnitityMappingAttribute;
if (attr != null)
{
tableName = attr.TableName;//表名只有获取一次
break;
}
}
if (string.IsNullOrEmpty(tableName))
{
tableName = objType.Name;
}
Console.WriteLine(string.Format("The TableName of the entity is:{0} ", tableName));
if (listColumnName.Count > 0)
{
Console.WriteLine("The Columns of the table are as follows:");
foreach (string item in listColumnName)
{
Console.WriteLine(item);
}
}
} static void Main()
{
DisplaySelfAttribute<Member>(); //显示结果
Console.ReadLine();
}
}
}
最终呈现的效果:
这里简单说一下AttributeUsage的一些用法,AttributeUsage 有三个 属性 ,分别是
public bool AllowMultiple { get; set; } 作用:是否能在一个目标身上多次使用
public bool Inherited { get; set; } 作用 :特性是否能继承到子类身上
public AttributeTargets ValidOn { get; } 作用:设置特性的可使用范围
这里面就是要解释一下AttributeTargets 的特性使用范围,这个主要是用在继承自Attribute的子类里面,在本例中我们自定义的特性主要用于标识类和属性
public enum AttributeTargets
{
// 摘要:
// 可以对程序集应用特性。
Assembly = 1,
//
// 摘要:
// 可以对模块应用特性。
Module = 2,
//
// 摘要:
// 可以对类应用特性。
Class = 4,
//
// 摘要:
// 可以对结构应用特性,即值类型。
Struct = 8,
//
// 摘要:
// 可以对枚举应用特性。
Enum = 16,
//
// 摘要:
// 可以对构造函数应用特性。
Constructor = 32,
//
// 摘要:
// 可以对方法应用特性。
Method = 64,
//
// 摘要:
// 可以对属性应用特性。
Property = 128,
//
// 摘要:
// 可以对字段应用特性。
Field = 256,
//
// 摘要:
// 可以对事件应用特性。
Event = 512,
//
// 摘要:
// 可以对接口应用特性。
Interface = 1024,
//
// 摘要:
// 可以对参数应用特性。
Parameter = 2048,
//
// 摘要:
// 可以对委托应用特性。
Delegate = 4096,
//
// 摘要:
// 可以对返回值应用特性。
ReturnValue = 8192,
//
// 摘要:
// 可以对泛型参数应用特性。
GenericParameter = 16384,
//
// 摘要:
// 可以对任何应用程序元素应用特性。
All = 32767,
}
谈谈对C#中反射的一些理解和认识(上)的更多相关文章
- 谈谈对C#中反射的一些理解和认识(下)
在上一篇中我们列举了一些反射的常规的使用,这一篇我们将介绍一些关于关于反射的高级属性,这些包括创建对反射的性能的总结以及如何优化反射性能,以及通过InvokeMember的方法如何去调用反射等等,通过 ...
- 在C++中反射调用.NET(一)
为什么要在C++中调用.NET 一般情况下,我们常常会在.NET程序中调用C/C++的程序,使用P/Invoke方式进行调用,在编写代码代码的时候,首先要导入DLL文件,然后在根据C/C++的头文件编 ...
- 转载 CSDN 谈谈我对证券公司一些部门的理解(前、中、后台)
谈谈我对证券公司一些部门的理解(前.中.后台) 2018年02月08日 15:11:07 unirong 阅读数:2165 文中对各大部门的分析都是从作者多年经历总结出来的有感之谈,尤其是前台的6 ...
- 谈谈我对证券公司一些部门的理解(前、中、后台)[z]
[z]https://blog.csdn.net/UniRong/article/details/79289947 文中对各大部门的分析都是从作者多年经历总结出来的有感之谈,尤其是前台的6大部门(经纪 ...
- 【原】谈谈对Objective-C中代理模式的误解
[原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...
- (转)谈谈RTP传输中的负载类型和时间戳
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://ticktick.blog.51cto.com/823160/350142 最近被 ...
- Golang的反射reflect深入理解和示例
编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examin ...
- 【FFMPEG】谈谈RTP传输中的负载类型和时间戳
谈谈RTP传输中的负载类型和时间戳 最近被RTP的负载类型和时间戳搞郁闷了,一个问题调试了近一周,终于圆满解决,回头看看,发现其实主要原因还是自己没有真正地搞清楚RTP协议中负载类型和时间戳的含义.虽 ...
- [每日一题]面试官问:谈谈你对ES6的proxy的理解?
[每日一题]面试官问:谈谈你对ES6的proxy的理解? 关注「松宝写代码」,精选好文,每日一题 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...
随机推荐
- springBoot 搭建web项目(前后端分离,附项目源代码地址)
springBoot 搭建web项目(前后端分离,附项目源代码地址) 概述 该项目包含springBoot-example-ui 和 springBoot-example,分别为前端与后端,前后端 ...
- ROS 创建服务和请求
教程 维基 http://wiki.ros.org/cn/ROS/Tutorials 快速过程 创建包 $ cd ~/catkin_ws $ mkdir ~/catkin_ws/src $ cd ~/ ...
- ORA-28040: No matching authentication protocol
1.2 前言部分 1.2.1 导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~: ① 告警日志中频繁出现Using depr ...
- a,b为2个整型变量,在不引入第三个变量的前提下写一个算法实现 a与b的值互换
package com.Summer_0424.cn; /** * @author Summer * a,b为2个整型变量,在不引入第三个变量的前提下写一个算法实现 a与b的值互换? */ publi ...
- 深蓝词库转换2.2发布,支持手心输入法和Win10微软拼音
距离上一次大版本的发布已经很久很久了,中间是不是会收到一些用户的来信,提出新的需求,于是只是做小版本的更新,终于积累了一些更新后,打算做个大版本的发布了. 深蓝词库转换是一个输入法的词库互转和生成软件 ...
- JVM调优常用参数和注意点备忘录
本文主要是工作过程中总结的一些jvm调优的参数和注意的地方,作为一个备忘录,先占个坑,有时间在来细化具体的实例. gc日志是覆盖的方式如果文件名字固定会导致上一次被覆盖可以采用这个-Xloggc:ba ...
- JS表格分页(封装版)
HTML代码: <html> <head> <meta charset='utf-8'> <script type="text/javascript ...
- 第一次在新西兰组织技术社区活动:Monkeyfest2018
从3月份登陆到现在,转眼间已经8个月了.在6个月的时候我就想写篇文总结下近期的一些状况,一直拖到现在.因为近期一直在筹备我第一次社区活动——Monkeyfest 2018,占用了比较多的时间.这是一个 ...
- .net Core 调用微信Jsapi接口,H5解析二维码
项目里需要用到扫描二维码,自己实现,不会. 找到了两种解决方案: 通过reqrcode.js,这是一个前端解析二维码内容的js库.如果二维码比较清晰,用这种效果也不错 调用微信扫一扫功能,这种效果很好 ...
- UnderWater+SDN论文之三
Software-Defined Underwater Acoustic Modems: Historical Review and the NILUS Approach Source: IEEE J ...