zoukankan      html  css  js  c++  java
  • C#反射

    反射的概念: 反射提供了封装程序集、模块和类型的对象(Type类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。

    一般使用:    工厂类,通过反射创建类的实例,实现层与层之间的解耦:  数据层→数据会话层→业务逻辑层。 其中,数据会话层通过反射创建数据层的实例,业务逻辑层调用。

    反射Type中的函数

    //判断两个成员是否存在继承关系    --后者继承于前者
    bool b= typeof(Person).IsAssignableFrom(typeof(Student));    //student继承了person
    
    //判断当前类是否为对象的实例
    Student st = new Student();
    Person p = new Person();
    bool s = typeof(Person).IsInstanceOfType(st);     //student继承了person  结果为true 
    bool b = p.GetType().IsInstanceOfType(st);   //结果为true   GetType当前对象的实例
    
    //判断一个类是否为另外一个类的子类    --子类放先 
    bool c=    typeof(Person).IsSubclassOf(typeof(Student));  
    
    //判断一个类是否为抽象类
    typeof(Class).IsAbstract

    反射中常用类的使用

    需求:通过反射获得Common程序集中的成员,并使用成员

    1、把Common.dll放到该应用程序的bin/Debug目录下

    string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Common.dll");
    Assembly ass = Assembly.LoadFile(path);  //需要绝对路径  LoadFile加载路径程序集内容        -->也不一定要在debug目录下,自己构建绝对路径也可
    Type[] tp = ass.GetTypes();             //获得程序集中的所有类型    GetExportedTypes();获取公共类型

    2、可以遍历程序集中的类型,获取类型的命名空间和类型名称

    foreach (Type item in tp)
    { 
        Console.WriteLine(item.Name);             //类型名称  --也就是common下类或者接口的名称
        Console.WriteLine(item.Namespace);        //命名空间
    }

    3、创建type对象

          a:创建没有构造函数的对象

    object o=  ass.CreateInstance("Common.FileCommon");     //FileCommom为Common命名空间的一个类 → 命名空间.类名   

        b:反射出来的类型有构造函数

     Type type = ass.GetType("Common.FileCommon");    //获得指定名称的Type对象
     object o = Activator.CreateInstance(type, "参数");

    注: 当反射出来的类型如果有构造函数,用上面代码中 ass.CreateInstance则会出现错误,如果有构造函数,那么该如何知道构造函数的参数?

     ConstructorInfo [] info= type.GetConstructors();    //查询所有的构造函数,可以看到构造函数需要传递参数的参数类型

    4、获得数据类型中所有的属性

     PropertyInfo  [] pinfo   = type.GetProperties();   //获取属性  然后可以遍历

    5、获得数据类型中所有的函数

    MethodInfo [] minfo =type.GetMethods();   //获取所有的函数

    6、目的:调用函数

     MethodInfo method= type.GetMethod("WriteData");    //该类中的writeData方法
     method.Invoke(o, "writeData方法的参数");     //o为上文创建的type对象

    综合: 当获得一个  .dll程序集的时候,需要先获取所有的类型,也就是这个程序集中的类,然后根据所需要类的名称,去创建指定名称的对象 如:Type type = ass.GetType("Common.FileCommon");  ,然后利用type获取构造函数,所有函数,属性(还有一些可以 type.方法名  获取相应的需求)。再选择创建type对象的方法(构造或无构造)。然后根据获得的函数来调用,传入相应的参数。

    实例1:工厂类通过反射创建类的实例:

    步骤①:在Web.Config    (网页的为web.config,程序中为app.config) ,配置文件配置:

     <appSettings>
    <add key="AssemblyPath" value="Xsh.OA.DAL" />   //路径
    <add key="NameSpace" value="Xsh.OA.DAL" />     //命名空间
    </appSettings>

    步骤②:获取刚才配置的信息

    public static readonly string AssemblyPath = ConfigurationManager.AppSettings["AssemblyPath"];
    
    public static readonly string NameSpace = ConfigurationManager.AppSettings["NameSpace"];

    步骤③:创建类的实例:

     public static IUserInfoDal CreateUserInfoDal()
     {
        string fullClassName = NameSpace + ".UserInfoDal";
         return  CreateInstance(fullClassName) as IUserInfoDal;         //IUserInfoDal为UserInfoDal继承的接口。
     }
    
      private static object CreateInstance(string className)
      {
                var assembly= Assembly.Load(AssemblyPath);
    
                return assembly.CreateInstance(className);
      }
    
    //此时,在外界调用CreateUserInfoDal这个方法,就会创建了UserInfoDal的实例,然后根据该实例 点出方法

    实例2:使用反射制作关机插件

    特点:如果需要其他插件,添加路径下的 .dll文件即可,删除插件则删除相应的.dll文件

                //获得文件路径
    
                string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"plug");   //bin/debug/plug存放.dll文件
                string[] files = Directory.GetFiles(path);
                foreach (string item in files)
                {
                   Assembly ass = Assembly.LoadFile(item);   
                   Type [] types=  ass.GetExportedTypes();
                    for (int i = 0; i < types.Length; i++)
                    {
                        //判断是否为接口中的类,并不是抽象类
                        if (typeof(IPlugin).IsAssignableFrom(types[i]) && !types[i].IsAbstract)
                        {
                            //创建对象
                            object  o =  Activator.CreateInstance(types[i]);
                            //获得指定对象
                            PropertyInfo psi=   types[i].GetProperty("Name");
                            object o2=  psi.GetValue(o);
                            //添加到菜单栏(这是winform下的一个菜单栏控件)
                            ToolStripItem tsi= PluginToolStripMenuItem.DropDownItems.Add(o2.ToString());
                            //注册单击事件
                             tsi.Tag = types[i];    //把数据对象存储到要使用的对象
                                                    //  tsi.Click += Tsi_Click;
                            tsi.Click += (s, e2) => {
    
                                Type t = tsi.Tag as Type;
                                MethodInfo mi = t.GetMethod("DoIt");
                                mi.Invoke(o, new object[] { });
                            };
                        }
                    }

    总结:  很多.dll文件可以通过反射的方式来获取相应的类,类的方法属性的使用,一些应用程序也可以通过反编译软件来获取一些方法属性等。(后面如果使用到另外用途,再加补充)

  • 相关阅读:
    AOP第一个例子
    初学Spring
    MyBatis延迟加载,缓存的使用
    MyBatis关联查询
    MyBatis的基本操作(02)-----Seeeion.commit引起事务的提交,多条件查询,智能标签的应用,ResultMap结果映射
    Js练习题之查找字符串中出现最多的字符和个数
    Js练习题之字符串转驼峰
    Js笔试题之正则表达式
    Js笔试题之千分位格式化
    Js笔试题之parseInt()和.map()
  • 原文地址:https://www.cnblogs.com/xsh-cs/p/8470055.html
Copyright © 2011-2022 走看看