谈谈对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,  
   }  

  

转载于:https://www.cnblogs.com/seekdream/p/8477329.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值