今天就平常用到的非常多的反射这个技术来做一个总结,当然关于反射需要讲解的东西实在是太多的内容,在一片文章中想要讲解清楚是非常难的,本篇博客也是就自己本人对这些内容学习后的一个总结,当然包括看书和自己写过的一些代码中抽取的一些示例,而且本文也仅限于此时对于这个知识点的理解,希望通过以后的逐步学习能够不断加深对这个知识点的理解。

  首先来看看对于反射的基础知识点。

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#中反射的一些理解和认识(上)的更多相关文章

  1. 谈谈对C#中反射的一些理解和认识(下)

    在上一篇中我们列举了一些反射的常规的使用,这一篇我们将介绍一些关于关于反射的高级属性,这些包括创建对反射的性能的总结以及如何优化反射性能,以及通过InvokeMember的方法如何去调用反射等等,通过 ...

  2. 在C++中反射调用.NET(一)

    为什么要在C++中调用.NET 一般情况下,我们常常会在.NET程序中调用C/C++的程序,使用P/Invoke方式进行调用,在编写代码代码的时候,首先要导入DLL文件,然后在根据C/C++的头文件编 ...

  3. 转载 CSDN 谈谈我对证券公司一些部门的理解(前、中、后台)

    谈谈我对证券公司一些部门的理解(前.中.后台) 2018年02月08日 15:11:07 unirong 阅读数:2165   文中对各大部门的分析都是从作者多年经历总结出来的有感之谈,尤其是前台的6 ...

  4. 谈谈我对证券公司一些部门的理解(前、中、后台)[z]

    [z]https://blog.csdn.net/UniRong/article/details/79289947 文中对各大部门的分析都是从作者多年经历总结出来的有感之谈,尤其是前台的6大部门(经纪 ...

  5. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  6. (转)谈谈RTP传输中的负载类型和时间戳

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://ticktick.blog.51cto.com/823160/350142 最近被 ...

  7. Golang的反射reflect深入理解和示例

    编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examin ...

  8. 【FFMPEG】谈谈RTP传输中的负载类型和时间戳

    谈谈RTP传输中的负载类型和时间戳 最近被RTP的负载类型和时间戳搞郁闷了,一个问题调试了近一周,终于圆满解决,回头看看,发现其实主要原因还是自己没有真正地搞清楚RTP协议中负载类型和时间戳的含义.虽 ...

  9. [每日一题]面试官问:谈谈你对ES6的proxy的理解?

    [每日一题]面试官问:谈谈你对ES6的proxy的理解? 关注「松宝写代码」,精选好文,每日一题 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...

随机推荐

  1. SQL Access Advisor in Oracle Database 10g

    The SQL Access Advisor makes suggestions about indexes and materialized views which might improve sy ...

  2. jenkins使用5----gi服务器搭建连接

    ♦安装git ♦服务器创建git用户 [root@localhost home]# id git id: git:无此用户 [root@localhost home]# useradd git [ro ...

  3. Vim 安装 YouCompleteMe

    Vim 下的自动补全,最好的工具莫过于 YouCompleteMe,官方文档在这里 http://valloric.github.io/YouCompleteMe/ 安装稍显复杂,以下记录我的过程. ...

  4. bootstraptable 分页查询

    1.前端配置 2.后台输出格式化数据 1.前端配置 @{ Layout = null; } <!DOCTYPE html> <html> <head> <me ...

  5. JAVA 垃圾收集算法,垃圾收集器与内存分配策略(内容全面,解析简单易懂)

    垃圾收集器需要解决的三个问题: 1)哪些内存需要回收 2)什么时候回收 3)如何回收 背景:程序计数器,虚拟机栈,本地方法栈3个区域随线程而生,随线程而灭,在这几个区域内不需要过多的考虑回收的问题,因 ...

  6. SkylineGlobe7.0.1版本 主页面如何和Popup里面的嵌入页面相互传值

    不想多说废话,直接看代码吧!(支持IE和Chrome) 主页面: function ShowPanel() { var sg = CreateSGObj(); var pp = sg.Creator. ...

  7. arm汇编之 bne与beq

    在网上看了一些bne和beq的区别,但是对于初学者来说,容易越看越糊涂,因此简单介绍下: 我们先分析CPSR寄存器的Z标识位: cmp指令可以直接影响CPSR寄存器的Z标识位(条件位),从图中可以看出 ...

  8. 【redis】1.redis-windows安装+配置介绍

    1.下载windows版本redis 官方下载地址:http://redis.io/download,不过官方没有64位的Windows下的可执行程序,目前有个开源的托管在github上, 地址:ht ...

  9. Java线程和线程池

    Android中创建线程的方式有,new Thread,new Thread(Runnable),new Thread(Callable)的形式. A. 直接new Thread简单方便. B. ne ...

  10. H5 61-浮动元素贴靠现象

    61-浮动元素贴靠现象 <!DOCTYPE html><html lang="en"><head> <meta charset=" ...