C#反射Reflection获取某个类属性,方法等相关信息,以及使用反射对方法的调用

83 篇文章 3 订阅

C#的反射System.Reflection正对于C#的整体代码结构:

命名空间Namespace一般与程序集Assembly名称一致。

一个程序集Assembly由多个类型Type【interface,class,struct,enum,delegate】组成。

一个类型Type由方法Method,字段Field,属性Property,事件Event等成员等组成。

一个属性Property可能含有特性Attribute。

一个方法Method有返回类型,方法名,参数列表,是否是静态等组成

方法的参数Parameter有类型,参数名,默认值,是否引用参数ref,是否输出参数out

一、新建.net core控制台应用程序ReflectionDemo,右键 解决方案-->添加---->新建项目

选择类库项目,输入类库名称TestClassLibrary。

右键控制台项目ReflectionDemo,添加 引用 ,勾选项目 TestClassLibrary,点击 确定。

二、删除类库TestClassLibrary的默认类Class1.cs。新建两个类Employee.cs和TestClass.cs

1).Employee.cs的源程序如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace TestClassLibrary
{
    /// <summary>
    /// 员工信息类
    /// </summary>
    public class Employee
    {
        /// <summary>
        /// 编号
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// 姓名
        /// </summary>
        [DisplayName("员工姓名")]
        public string Name { get; set; }
        /// <summary>
        /// 地址
        /// </summary>
        public string Address { get; set; }
        /// <summary>
        /// 入职日期
        /// </summary>
        public DateTime JoinDate { get; set; }

        /// <summary>
        /// 打印员工信息
        /// </summary>
        public void PrintMessage() 
        {
            Console.WriteLine($"编号:{Id},姓名:{Name},地址:{Address},入职日期:{JoinDate}");
        }
    }
}

2).TestClass.cs的源程序如下:

using System;

namespace TestClassLibrary
{
    /// <summary>
    /// 测试类
    /// </summary>
    public class TestClass
    {
        /// <summary>
        /// 加法
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static int Add(int x, int y = 2)
        {
            return x + y;
        }

        /// <summary>
        /// 减法
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static int Subtract(int x, int y)
        {
            return x - y;
        }

        /// <summary>
        /// 获取数组的最大数以及最大数所在的索引
        /// </summary>
        /// <param name="array">数组</param>
        /// <param name="maxIndex">输出最大值的所在的索引</param>
        /// <returns></returns>
        public int GetMaxNumber(int[] array, out int maxIndex)
        {
            if (array == null || array.Length == 0)
            {
                Console.WriteLine("数组不能为null,数组的长度也不能为,暂定返回值为-1");
                maxIndex = -1;
                return -1;
            }
            int max = array[0];
            maxIndex = 0;
            for (int i = 1; i < array.Length; i++)
            {
                if (max < array[i])
                {
                    maxIndex = i;
                    max = array[i];
                }
            }
            return max;
        }

        /// <summary>
        /// 获得不定项数组的长度
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public int GetVaryArrayLength(params int[] array)
        {
            if (array == null)
            {
                return 0;
            }
            return array.Length;
        }

        /// <summary>
        /// 测试带ref的参数
        /// </summary>
        /// <param name="inParameter"></param>
        /// <param name="refParameter"></param>
        public void TestReference(int inParameter, ref int refParameter)
        {
            inParameter = 5;
            refParameter = 2;
            Console.WriteLine("参数默认为输入参数,如:inParameter,不会改变原来的值.\r\n带ref或者out的参数是引用参数,如:refParameter,可以改变原来的值.");
        }

        /// <summary>
        /// 私有方法无法通过反射得到该方法的信息
        /// </summary>
        private void PrivateMethod()
        {
            Console.WriteLine("私有方法");
        }

    }
}

三、ReflectionDemo控制台的默认类Program用于测试反射调用相关信息,源程序如下:

using System;
using System.Reflection;

namespace ReflectionDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly assembly = Assembly.Load("TestClassLibrary");
            Console.WriteLine($"程序集名称:{assembly.FullName}");
            Type[] types = assembly.GetTypes();
            for (int i = 0; i < types.Length; i++)
            {
                Console.WriteLine($"第【{i + 1}】个类型【{types[i].FullName}】,所有的方法列表如下:");
                MethodInfo[] methodInfos = types[i].GetMethods();
                for (int j = 0; j < methodInfos.Length; j++)
                {
                    Console.WriteLine($"    第【{j + 1}】个方法【{methodInfos[j].Name}】.返回类型:{methodInfos[j].ReturnType},是静态方法:{methodInfos[j].IsStatic},是公共方法:{methodInfos[j].IsPublic}");
                    Console.WriteLine($"    方法【{methodInfos[j].ReturnType} {methodInfos[j].Name}】的参数如下:");
                    //方法所对应的参数信息:
                    ParameterInfo[] parameterInfos = methodInfos[j].GetParameters();
                    for (int k = 0; k < parameterInfos.Length; k++)
                    {
                        //方法的类型是引用类型时(带有"&"表示引用类型) 如:System.Int32&,此时参数带ref或out修饰
                        //如果参数是输出参数(paras[k].IsOut==true),则参数的修饰是out,否则是ref
                        Console.WriteLine($"        第【{k + 1}】个参数{parameterInfos[k].ParameterType} {parameterInfos[k].Name},是否输出参数:{parameterInfos[k].IsOut},是否存在默认值:{parameterInfos[k].HasDefaultValue},默认值:{parameterInfos[k].DefaultValue}");
                    }
                }
                Console.WriteLine();
            }

            Console.WriteLine("当我们知道方法的名称,返回值信息和参数信息时,就可以反射调用该方法或构造函数了.");
            TestInvokeMethod();
            Console.WriteLine("下面测试类的属性(get,set)信息...");
            TestProperty();
            Console.ReadLine();
        }

        /// <summary>
        /// 测试调用类库中的方法
        /// </summary>
        static void TestInvokeMethod()
        {
            Type ty = Assembly.Load("TestClassLibrary").GetType(string.Format("{0}.{1}", "TestClassLibrary", "TestClass"));
            Console.WriteLine("调用TestClassLibrary.TestClass 类的公共静态方法public static int Add(int x, int y=2) 的例子");
            MethodInfo mi = ty.GetMethod("Add");

            //调用静态方法Add时,Invoke的第一个参数为null
            object returnValue = mi.Invoke(null, new object[] { 4, 5 });
            Console.WriteLine("Add方法的返回值:{0}\r\n", returnValue);

            Console.WriteLine("调用TestClassLibrary.TestClass 类的公共实例化方法public int GetMaxNumber(int[] array, out int maxIndex) 的例子");
            MethodInfo mi1 = ty.GetMethod("GetMaxNumber");

            //调用实例化方法(非静态方法)需要创建类型的一个实例
            object instanceObject = Activator.CreateInstance(ty);
            int maxIndex = -1;
            object[] parametersInfo = new object[] { new int[] { 8, 20, 15, 36, 1, 4 }, maxIndex };

            //调用实例化方法GetMaxNumber时,Invoke的第一个参数是一个实例化对象
            object returnValue1 = mi1.Invoke(instanceObject, parametersInfo);
            maxIndex = Convert.ToInt32(parametersInfo[1]);
            Console.WriteLine("GetMaxNumber方法的返回值(最大值):{0},最大值的索引:{1}", returnValue1, maxIndex);
        }

        /// <summary>
        /// 测试属性信息
        /// </summary>
        static void TestProperty() 
        {
            Type type = Assembly.Load("TestClassLibrary").GetType(string.Format("{0}.{1}", "TestClassLibrary", "Employee"));
            //调用实例化对象
            object instanceObject = Activator.CreateInstance(type);
            Console.WriteLine("propertyInfo.SetValue(类的实例化对象,当前属性对应类型的某个值)");
            PropertyInfo[] propertyInfos = type.GetProperties();
            for (int i = 0; i < propertyInfos.Length; i++)
            {
                PropertyInfo propertyInfo = propertyInfos[i];
                Console.WriteLine($"属性名称:{propertyInfo.Name},属性类型:{propertyInfo.PropertyType},对应的特性:{string.Join(",", propertyInfo.CustomAttributes)}");
                switch (propertyInfo.Name)
                {
                    case "Id":
                        propertyInfo.SetValue(instanceObject, 123);
                        break;
                    case "Name":
                        propertyInfo.SetValue(instanceObject, "扁络桓");
                        break;
                    case "Address":
                        propertyInfo.SetValue(instanceObject, "驭界枢");
                        break;
                    case "JoinDate":
                        propertyInfo.SetValue(instanceObject, DateTime.Now.AddYears(-3));
                        break;
                }
            }

            MethodInfo methodInfo = type.GetMethod("PrintMessage");
            methodInfo.Invoke(instanceObject, null);
        }

    }
}
四、程序运行如图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯内科

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值