C# 反射 笔记

一、基础

C#反射属于相对高级的话题,学会了反射,你可以给你自己的程序增加一些动态的功能。

要点:

1.程序集 Assembly类  

     load()    GetType()     CreateInstance()

2.Type类 

     主要函数 :

  • GetConstructor() 
  • GetEvent()

  • GetField()

  • GetMethod()

  • GetProperty()  

知道了以上函数,就可以应付大多数情况需要反射处理的情况

二、实例1 获取程序集中的类的信息

先写一个需要编译成dll的程序集

namespace Common
{
    public class Person
    {
        public event Action<int> blink;
        public event Action<string> blink2;
        public Person(int age, string name)
        {
            this.Age = age;
            this.Name = name;
        }
        public int Age { get; set; }
        public string Name { get; set; }

        private  int Age2 { get; set; }
        protected int Age3 { get; set; }

        public string Sex;
        private string Sex2;

   

        public void SayHello()
        {
            Console.WriteLine("我是Person类中的函数");
        }

        private void SayHello2()
        {
            Console.WriteLine("我是Person类中的函数2");
        }

        public void Write()
        {
            File.WriteAllText("Person.txt", "张三李四王五赵六田七");
        }
    }
}

下面是使用反射

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//反射  Assembly
using System.Reflection;
using System.IO;

namespace HelloReflection
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ClassLibrary1.dll");
            //首先加载程序集文件
            Assembly ass = Assembly.LoadFile(path);
            Console.WriteLine("加载程序集成功");
            #region 获得程序集中数据类型的3种方式
            //获得程序集中定义的所有类型,包括公开的和不公开的
            Type[] types = ass.GetTypes();
            //获得程序集中定义的公共类型
            //Type[] types = ass.GetExportedTypes();
            foreach (Type t in types)
            {
                Console.WriteLine(t.Name);
                Console.WriteLine(t.FullName);
                Console.WriteLine(t.Namespace);
            }
            //获得程序集中指定的类型
            Type type = ass.GetType("Common.Person");
            Console.WriteLine(type.Name);
            Console.WriteLine("----------");
            #endregion


            //从程序集中查找指定类型,然后使用系统激活器创建它的实例(实际上调用类型的默认无参构造函数)
            //object obj = ass.CreateInstance("Common.Person");

            //使用Activator动态创建带有自定义构造函数的类型的实例
            object obj = Activator.CreateInstance(type, 18, "张三");

            Console.WriteLine(obj.GetType());
            //获得数据源中的属性数组
            PropertyInfo[] pros = obj.GetType().GetProperties();
            foreach (PropertyInfo p in pros)
            {
                Console.WriteLine(p.Name);
            }
            Console.WriteLine();
            Console.WriteLine("methods");
            //获得数据源中的方法
            MethodInfo[] mds = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic |
            BindingFlags.Public);
            foreach (MethodInfo m in mds)
            {
                Console.WriteLine(m.Name);
            }

            Console.WriteLine();
            MethodInfo mdi = obj.GetType().GetMethod("SayHello2",BindingFlags.Instance | BindingFlags.NonPublic |
            BindingFlags.Public);
            mdi.Invoke(obj, null);

            Console.WriteLine();

            //获得数据源中的字段
            FieldInfo[] fis = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic |
            BindingFlags.Public);
            foreach (FieldInfo f in fis)
            {
                Console.WriteLine(f);
            }

            Console.WriteLine();
            //获得数据源中的构造函数
            ConstructorInfo[] cis = obj.GetType().GetConstructors();
            foreach (ConstructorInfo c in cis)
            {
                Console.WriteLine(c);
            }

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();


            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("----event------");

            EventInfo[] eifs = obj.GetType().GetEvents();
            foreach(var e in eifs)
            {
                Console.WriteLine(e);
            }

            Console.WriteLine();

            Console.ReadKey();
        }
    }
}

输出结果(部分)

从以上输出 结果可以看到

  1. 反射 GetMethods() 将属性的get,set也作为方法输出 
  2. 反射GetMethod()通过添加绑定标识BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public可以反射出类的私有函数并调用
  3. 反射GetFields()通过绑定标识也可以反射出类的私有字段,但是不加标识,默认只反射出公有字段,注意事件也算是字段(field)
  4. GetEvents()方法就是将类中的event事件列举出来。(关于event关键字,实际在C#编程中,用不用区别几乎没有,如果你注意内在美,可以加上这个词)

三.实例2  利用反射动态创建结构体的实例数组并赋值

需要编译成dll的结构体

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace Common
{

    public struct ServiceMsg
    {
        public int Id;
        public long NowTime;
    
    }

}


测试实例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//反射 Assembly需要的命名空间
using System.Reflection;
using System.IO;

namespace ReflectTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ClassLibrary1.dll");
            //首先加载程序集文件
            Assembly ass = Assembly.LoadFile(path);
            Console.WriteLine("加载程序集成功");
            //获得程序集中定义的所有类型,包括公开的和不公开的
            Type typeAss = ass.GetType("Common.ServiceMsg");
            //创建数组
            var InstanceArray = Array.CreateInstance(typeAss, 3);
           

            for (int i = 0; i < InstanceArray.Length; i++)
            {
                //使用get方法获取InstanceArray[i]
                //注意invoke参数i是指定数组中的索引值
                var serviceMsgItem = InstanceArray.GetType()
                    .GetMethod("Get", new Type[] { typeof(int) })
                    .Invoke(InstanceArray, new object[] { i });
                FieldInfo fiId = serviceMsgItem.GetType().GetField("Id");
                fiId.SetValue(serviceMsgItem, i+100);

                FieldInfo fiNowTime = serviceMsgItem.GetType().GetField("NowTime");
                fiNowTime.SetValue(serviceMsgItem, DateTime.Now.Ticks);

                InstanceArray.GetType()
                    .GetMethod("Set", new Type[] { typeof(int), serviceMsgItem.GetType() })
                    .Invoke(InstanceArray, new object[] { i, serviceMsgItem });
            }

      


         }


        
    }
}

执行结果(instanceArray被成功赋值):

 

要点:

  1.      Array.CreateInstance()创建数组 
  2. InstanceArray.GetType().GetMethod("Get", new Type[] { typeof(int) }).Invoke(InstanceArray, new object[] { i })  获取结构体数组其中一项
  3. InstanceArray.GetType()
                        .GetMethod("Set", new Type[] { typeof(int), serviceMsgItem.GetType() })
                        .Invoke(InstanceArray, new object[] { i, serviceMsgItem })  将值再设置回去,因为结构体是按值传递的

 

如果是类数组,注意Array.CreateInstance()创建的数组,每一项的值需要重新动态实例化一个类加入到instanceArray中,这里不再举例。

 

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值