zoukankan      html  css  js  c++  java
  • C#反射基础知识和实战应用

    首先来说一下什么是反射? 

    反射提供了封装程序集、模块和类型的对象(Type类型)

    可以使用反射动态的创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型,然后,可以调用类型的方法或访问其字段和属性 。

    总之,有了反射,以前很多实现不了的功能都可以实现。

    下面先来写一个小例子,体验一下反射是怎么一回事:

    打开VS2010,新建一个控制台应用程序,在program.cs里面写代码

    首先引入命名空间:

    using System.Reflection;

    下如下代码:

             PropertyInfo len = typeof(string).GetProperty("Length");
             string s = "Hello,reflection!";
             int length = (int)len.GetValue(s, null);
             Console.WriteLine(length.ToString());

    这里通过反射获取string的Length属性,并通过调用PropertyInfo 的GetValues方法获取属性值,其中GetValues方法的原型如下:

    public virtual object GetValue(object obj, object[] index);

    第一个参数obj是拥有此属性的类的实例,在这个例子中,为字符串s,s拥有Length属性。

    第二个参数为索引值,微软解释如下:

    Optional index values for indexed properties. This value should be null for non-indexed properties.

    一般情况下用null,大家可以自己深入研究一下。

    GetValues方法返回的是object类型,所以必须强制转换类型。

    下面通过反射来获取string的一个方法,看看方法是如何通过反射得到的,代码如下:

    string s = "Hello,reflection!";
    MethodInfo method = typeof(string).GetMethod("Contains");
    bool result = (bool)method.Invoke(s, new object[] { "Hello" });
    Console.WriteLine(result);

    其中,Invoke的方法定义如下:

    public object Invoke(object obj, object[] parameters);

    这个就很好理解了,第一个参数为拥有此方法的类的实例,还是为string实例s.

    第二个参数就是一个object数组的参数。

    这里调用的是string中的Contains方法,判断string中是否包含某个字符串。

    下面通过反射来实例化一个string对象,代码如下:

         Type t = Type.GetType("System.String");
             char[] para = new char[] { 'H', 'e', 'l', 'l', 'o' };
             var o = Activator.CreateInstance(t, para);
             Console.WriteLine(o);

    这个跟获取方法相似,唯一不同的就是string的构造方法参数是char[]数组,所以必须传入符合的类型。这里实例化了一个string,值为Hello。

    看到这里,你对反射已经有了初步的了解,下面开始进入实战应用:

    在解决方案上面点击鼠标右键,添加项目,选中类库,输入名称,添加一个类库。

    在类库中添加Custom类,代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ReflectionDll
    {
       public class Custom 
       {
          public string Name { get; set; }
          public string Address { get;set; }
          public int Age { get; set; }
          public DateTime BirthDay { get; set; }
    
          public string GetInfo(string name = "",int age = 0)
          {
             if (name == "" && age == 0)
             {
                return "Custom Name: " + this.Name + ",Age: " + this.Age;
             }
             else
             {
                return "Custom Name: " + name + ",Age: " + age;
             }
          }
       }
    }

    这里只声明了几个属性和一个方法,供演示使用。写好后编译一下,在控制台项目里面添加引用这个类库(为了方便,否则每次编译都要手动拷贝DLL到控制台项目下面),这样VS会自动将生成的DLL拷贝到控制台debug目录下,方便调用。下面开始使用反射来加载这个DLL,代码如下:

            string path = Environment.CurrentDirectory + "\ReflectionDll.dll";
             Assembly assem = Assembly.LoadFile(path);
             Type customType = assem.GetType("ReflectionDll.Custom");
             var custom = Activator.CreateInstance(customType);

    注意了,这里首先要获取DLL的物理路径,所以上面是否添加引用是无所谓的。有了路径后,通过Assembly的LoadFile方法加载DLL,再获取类的Type,注意GetType方法里面的参数必须为类的全称,及命名空间 + 类名,否则无法找到。

    最后一行,创建了一个类的实例,类型为object类型。

    下面来获取Custom的所有属性,代码如下:

    PropertyInfo[] propertys = customType.GetProperties();
    
             Console.WriteLine("******************************");
             foreach (PropertyInfo pro in propertys)
             {
                Console.WriteLine("PropertyName:" + pro.Name + "
    " +
                   "PropertyType:" + pro.PropertyType + "
    " +
                   "ClassName:" + pro.ReflectedType + "
    " +
                   "DLLName:" + pro.Module + "
    ");
             }
             Console.WriteLine("******************************");

    通过调用GetProperties方法获取所有属性,保存到PropertyInfo[]数组中,然后遍历数组输出属性值。

    下面是各个属性的含义:

    Name                      属性名称

    PropertyType          属性数据类型

    ReflectedType         所在的类的命名控件 + 类名

    Module                  所在的DLL文件名称

    设置某个属性的值,方法如下:

         PropertyInfo p = customType.GetProperty("Name");
         p.SetValue(custom, "CustomName",null);

    是不是很容易啊。。。

    下面来说一下,调用类的方法,和一些属性。代码如下:

             MethodInfo _method = customType.GetMethod("GetInfo");
             //显示方法名称
             Console.WriteLine("Invoke method:" + _method.Name);
             //显示返回的数据类型
             Console.WriteLine("Return type:" + _method.ReturnParameter);
             ParameterInfo[] parameters =  _method.GetParameters();
             foreach (ParameterInfo pa in parameters)
             {
                Console.WriteLine(pa.Name + pa.ParameterType + pa.Position + pa.Member);
             }
             
             object[] paras = new object[] { "Jack",24 };
    
             Console.WriteLine(_method.Invoke(custom, paras));
    同属性一样,参数可以通过GetParameters()来获取,获取的参数信息如下:

    Name 参数名称
    ParameterType 参数数据类型
    Position 参数的位置
    Member 输出所有参数

    调用有参数的方法时,需要传入参数,New一个object数组,将参数按顺序写入即可。

    补充内容:
    当类中存在重载方法时,直接获取方法名会报异常,可以通过参数来获取指定的重载方法:
    MethodInfo _method = customType.GetMethod("GetInfo",new Type[] {typeof(string),typeof(int)});
    
    
    
    提示:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    如果觉得还有帮助的话,可以点一下右下角的【推荐】,希望能够持续的为大家带来好的技术文章!想跟我一起进步么?那就【关注】我吧。
    如果对文章有任何问题,都可以再评论中留言,我会尽可能的答复您,谢谢你的阅读
  • 相关阅读:
    《入门经典》——6.15
    《Linear Algebra and Its Application》-chaper1-行化简法解决线性方程组
    《算法实战策略》-chaper19-队列、栈和双端队列
    《Linear Algebra and Its Applications》-chaper1-向量方程、矩阵方程和线性方程组
    辛普森法则
    《训练指南》——6.15
    《入门经典》——6.21
    《算法问题实战策略》-chaper13-数值分析
    Scheme 中的 pair 和 list 简述
    C. Friends
  • 原文地址:https://www.cnblogs.com/dabiaoge/p/4110403.html
Copyright © 2011-2022 走看看