zoukankan      html  css  js  c++  java
  • .NET C#利用反射获取类文件以及其中的方法&属性 并获取类及方法上的特性

    了解C#特性类并声明我们自己的特性类【AttributeTest】代码如下


    using System;
    
    namespace AttributeTest
    {
        /* 特性说明
        特性本质是一个继承和使用了系统基类的"类",用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。特性与程序实体关联后,
        即可在运行时使用名为“反射”的技术查询特性。
        官方介绍的很详细,我们就一起来了解一下它的用法。
    
        特性具有以下属性:
    
        1.特性可向程序中添加元数据。元数据是有关在程序中定义的类型的信息。所有的.NET 程序集都包含指定的一组元数据,
          这些元数据描述在程序集中定义的类型和类型成员。可以添加自定义特性,以指定所需的任何附加信息。
    
        2.可以将一个或多个特性应用到整个程序集、模块或较小的程序元素(如类和属性)。
    
        3.特性可以与方法和属性相同的方式接受参数。
    
        4.程序可以使用反射检查自己的元数据或其他程序内的元数据。
        */
    
        #region 声明一个 作用于成员方法 的特性
        //1.第一步 继承自定义属性的基类 Attribute
        //2.第二步 指定 我们自定义特性类 的一些属性,用系系统特性指定
        // AttributeTargets:指定为程序中的何种成员设置属性 可写多个 例: AttributeTargets.Class|AttributeTargets.Method
        //    AllowMultiple:如果允许为一个实例多次指定该特性,则为 true;否则为 false。默认为 false。
        //        Inherited:如果该属性可由派生类和重写成员继承,则为 true,否则为 false。默认为 true。
        [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
        public class MethodAttribute : Attribute 
        {
            /// <summary>
            /// 方法名称
            /// </summary>
            public string MethodName { set; get; }
            /// <summary>
            /// 方法描述
            /// </summary>
            public string MethodDesc { set; get; }
    
            /// <summary>
            /// 方法描述特性
            /// </summary>
            /// <param name="methodName">方法名称</param>
            /// <param name="methodDescription">方法描述</param>
            public MethodAttribute(string methodName, string methodDescription)
            {
                MethodName = methodName;
                MethodDesc = methodDescription;
            }
        }
        #endregion
    
        #region 声明一个 作用于类 的特性
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]//第一步
        public class ClassAttribute : Attribute//第二步
        {
            string ClassName { set; get; }
            string ClassDesc { set; get; }
    
            public ClassAttribute(string className, string classDesc)
            {
                ClassName = className;
                ClassDesc = classDesc;
            }
    
            //重写当前特性的ToString()方法
            public override string ToString()
            {
                return string.Format(@"当前类特性名:[ClassAttribute]
                    特性成员1:ClassName-->值:{0},
                    特性成员2:ClassDesc-->值:{1}", ClassName, ClassDesc);
            }
        }
        #endregion
    }
    

      

    编写使用了自定义特性类的类及成员 代码如下

    using System;
    
    namespace AttributeTest
    {
        #region 为一个类编写成员 并使用自定义的类特性以及成员特性 
        [ClassAttribute("TestClass", "测试反射及特性")]
        class TestClass
        {
            string _StrTest = "测试信息";
            float _Version = 1.1F;
            float Version { set { _Version = value; } get { return _Version; } }
            string StrTest { set { _StrTest = value; } get { return _StrTest; } }
    
            public TestClass()
            {
    
            }
    
            TestClass(string strTest,float version)
            {
                StrTest = strTest;
                Version = version;
            }
    
            #region 用于测试反射执行私有非静态方法(带有自定义方法成员特性)---> 成员1
            [MethodAttribute("Demo", "测试特性类示例方法Demo")]
            string Demo(string param)
            {
                return string.Format("
    1.方法调用信息:
    ①调用方法:{0}
    ②传递参数:{1}", "Demo", param);
            }
            #endregion
    
            #region 用于测试反射执行公开静态方法(带有自定义方法成员特性)---> 成员2
            [MethodAttribute("Demo1", "测试特性类示例方法Demo1")]
            public static string Demo1(string param)
            {
                return string.Format("
    1.方法调用信息:
    ①调用方法:{0}
    ②传递参数:{1}", "Demo1", param);
            }
            #endregion
    
            public void ConsoleMsg(string strMsg)
            {
                Console.WriteLine("
    Msg:"+strMsg);
            }    
        }
        #endregion
    
    }
    

     

    通过反射机制 获取所编写类文件及其成员 和其特性 代码如下

    using System;
    using System.Reflection;
    
    namespace AttributeTest
    {
        class Program
        {
            #region 存储 TestClass类反射信息 的字段
            static Type clazz;
            static Type clazz1;
            static Type clazz2;
            static Type clazz3;
            #endregion
    
            static void Main(string[] args)
            {
                Program program = new Program();    
                program.GetReflectInfoByClass();              //得到TestClass类的反射
                program.ReflectInvokePrivateNonStaticMethod();//反射的方式调用TestClass类中私有非静态方法 并输出其方法上的特性
                program.ReflectInvokePublicStaticMethod();    //反射的方式调用TestClass类中公开静态方法 并输出其方法上的特性
                program.GetAllField();                        //获取TestClass类中的 字段
                program.GetAllProp();                         //获取TestClass类中的 属性
                program.ReflectGetAttributeByClass();         //获取TestClass类上的 特性
    
                Console.ReadKey();
            }
    
            #region 通过【类名】和【类的限定名】和 【程序集(Assembly)】取得类的【反射信息】
            //通过类名和类的限定名取得类的反射信息
            void GetReflectInfoByClass()
            {
                //以下三种种方式得到当前类的反射信息 得到的结果都一样
    
                //1.通过TestClass类名得到类反射信息
                clazz = typeof(TestClass);
                clazz1 = new TestClass().GetType();
    
                //2.通过TestClass类的限定名得到其反射信息
                clazz2 = Type.GetType("AttributeTest.TestClass");
    
                //3.通过【程序集.dll】或【可执行文件.exe】反射TestClass
                Assembly assembly = Assembly.LoadFile(@"F:Projects_C#UpLoadData_prjAttributeTestinDebugAttributeTest.exe");
                clazz3 = assembly.GetType("AttributeTest.TestClass");
    
                //判别得到的反射是否一致
                if (clazz.Equals(clazz2) && clazz2.Equals(clazz3))
                    Console.WriteLine("
    clazz==clazz1==clazz2==clazz3
    ");
    
                //直接利用 程序集和类的完全限定名 创建TestClass对象 调其方法
                var obj = assembly.CreateInstance("AttributeTest.TestClass");
                if (obj is TestClass)
                {
                    TestClass tc = obj as TestClass;
                    tc.ConsoleMsg("反射会破坏访问权限");      
                }
            }
            #endregion
    
            #region 用反射的方式调用【TestClass类】私有非静态方法
            /// <summary>
            /// 用反射的方式调用TestClass类中私有非静态方法
            /// </summary>
            void ReflectInvokePrivateNonStaticMethod()
            {
                //Demo为私有方法 指定在类中搜索私有成员|实例成员
                BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
    
                //反射私有方法需要指定 BindingFlags.NonPublic
                var Demo = clazz1.GetMethod("Demo", bindingFlags);//私有非静态
    
                #region 调用私有非静态方法[Demo]
                //1.实例化[Demo]方法所在类, 第二个参数默认false:不可访问私有构造函数  true:则可访问类中私有构造函数
                object o = Activator.CreateInstance(clazz2, true);
    
                //2.通过类的实例调用方法[Demo] (含一个参数)
                var returns = Demo.Invoke(o, new object[] { "ReflectionTest" });
                Console.Write(returns);
                #endregion
    
                //输出方法上的特性信息
                ReflectGetAttributeByMethod(Demo);
                Console.Write("
    ");
            }
    
            #endregion
    
            #region 用反射的方式调用【TestClass类】中公开静态方法
            /// <summary>
            /// 用反射的方式调用TestClass类中公开静态方法
            /// </summary>
            void ReflectInvokePublicStaticMethod()
            {
                #region 调用公开静态方法
                //1.Demo1为公开访问权限,BindingFlags默认为 Instance、Public
                var Demo1 = clazz2.GetMethod("Demo1");
    
                //2.Demo1为静态方法 调用不需要实例化其所在类
                var returns = Demo1.Invoke(clazz, new object[] { "ReflectionTest1" });
    
                //输出方法返回值
                Console.Write(returns);
                #endregion
    
                //通过反射信息得到方法上的特性信息
                ReflectGetAttributeByMethod(Demo1);
                Console.WriteLine("
    ");
            }
            #endregion
    
            #region 通过 【方法反射信息】 得到方法使用的特性
            /// <summary>
            /// 通过方法的反射信息得到方法使用的特性
            /// </summary>
            /// <param name="method"></param>
            void ReflectGetAttributeByMethod(dynamic method)
            {
                if (method == null)
                {
                    Console.WriteLine("参数不能为空!,按任意键结束!");
                    Console.ReadKey();
                    return;
                }
    
                //得到当前方法上的特性类 信息
                MethodAttribute methodAttribute = Attribute.GetCustomAttribute(method, typeof(MethodAttribute));
                if (methodAttribute != null)
                {
                    Console.WriteLine("
    2.输出当前方法特性信息:");
                    Console.WriteLine("①当前调用方法名称:[" + methodAttribute.MethodName + "]");
                    Console.WriteLine("②方法描述:[" + methodAttribute.MethodDesc + "]");
                }
                else
                {
                    Console.WriteLine("
    当前传入的方法没有反射信息!
    ");
                }
            }
    
            #endregion
    
            #region 获取【类】的 特性 信息
            /// <summary>
            /// 获取修饰类的 特性 信息
            /// </summary>
            void ReflectGetAttributeByClass()
            {
                Attribute attribute = Attribute.GetCustomAttribute(clazz2, typeof(Attribute));
                if (attribute != null)
                {
                    Console.WriteLine(attribute.ToString());
                }
            }
            #endregion
    
            #region 获取【字段】并得其值
            //获取字段并得到字段的值
            void GetAllField()
            {
                //获取构造函数 公开无参的构造方法
                var constructor = clazz.GetConstructor(new Type[0]);
    
                //通过构造函数的调用获取对象
                var TestClass = constructor.Invoke(new object[0]);
    
                //获取所 实例 私有 字段
                FieldInfo[] fields = clazz.GetFields(BindingFlags.Instance|BindingFlags.NonPublic);
                
                //循环遍历字段和其值
                foreach (FieldInfo field in fields)
                {
                    Console.WriteLine("
    字段:"+field.Name+",值:"+field.GetValue(TestClass).ToString()+"
    ");
                }
            }
    
            #endregion
    
            #region 获取【属性】并得其值
            //获取属性并得到属性的值
            void GetAllProp()
            {
                //获取有两个参数私有非静态的构造方法
                var constructor = clazz.GetConstructor(
              BindingFlags.Instance|BindingFlags.NonPublic,//方法修饰符
              System.Type.DefaultBinder,//获取对默认绑定器的引用,该绑定器实现用于选择的内部规则
              new Type[] { typeof(string),typeof(float)},//构造函数的两个参数形参类型
              new ParameterModifier[] { new ParameterModifier(2)});//为构造函数的结构 指定参数的个数
    
                //通过构造函数 获得实际对象
                var TestClass = constructor.Invoke(new object[] { "测试",2.2F});
    
                //获取所有 实例 私有 属性
                PropertyInfo[] propertyInfos = clazz.GetProperties(BindingFlags.Instance|BindingFlags.NonPublic);
    
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    Console.WriteLine("
    属性名:"+propertyInfo.Name+"属性值:"+propertyInfo.GetValue(TestClass)+"
    ");
                }
                //循环获取所获取属性的值
            }
            #endregion
    
        }
    }
    

      

  • 相关阅读:
    PA
    核电站问题(codevs 2618)
    [转]SQL SERVER 的排序规则
    C# 窗体控件输入框大写
    查看哪些端口被使用
    [转]Windows服务“允许服务与桌面交互”的使用和修改方法
    [转]OBJECT_ID 有哪些种类
    如何:对 Windows 窗体控件进行线程安全调用
    老人手机不要买山寨机
    VBA文本型数字变成数值
  • 原文地址:https://www.cnblogs.com/JourneyOfFlower/p/10390844.html
Copyright © 2011-2022 走看看