反射

参考:反射基础

反射用于在程序运行过程中,获取类里面的信息或发现程序集并运行的一个过程。通过反射可以获得.dll和.exe后缀的程序集里面的信息。使用反射可以看到一个程序集内部的类,接口,字段,属性,方法,特性等信息。

在System.Reflection命名空间内包含多个反射常用的类,下面表格列出了常用的几个类。

下面的Demo用了Assembly、MethodInfo、PropertyInfo(反射特性请移步到asp.net MVC 特性(Attributes)的简单应用--属性特性

首先一个添加一个保存反射信息的类AssemblyResult

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

namespace ReflectionTest
{
    /// <summary>
    /// 保存反射信息的类
    /// </summary>
    class AssemblyResult
    {
        /// <summary>  
        /// 程序集名称  
        /// </summary>  
        public string AssemblyName { get; set; }

        public List<ClassInfo> ClassInfos { get; set; }

        public AssemblyResult() { }

        public AssemblyResult(string assemblyName)
        {
            this.AssemblyName = assemblyName;
        }
    }

    public class ClassInfo
    {
        /// <summary>
        /// 类名
        /// </summary>
        public string ClassName { get; set; }
        /// <summary>  
        /// 类的属性  
        /// </summary>  
        public List<string> Properties { get; set; }
        /// <summary>  
        /// 类的方法  
        /// </summary>  
        public List<string> Methods { get; set; }
    }
}

然后新建一个类库ClassLibrary1,里面新建一个类Person

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

namespace ClassLibrary1
{
    public class Person
    {
        private string name;
        public string Name { get; set; }

        private int age;
        public int Age { get; set; }

        public void Show() { Console.WriteLine("我是Person类里的Show方法!"); }

        public void Say() { Console.WriteLine("我的名字叫{0},我今年{1}岁", this.Name, this.Age); }

        public void Add(int i, int j) { Console.WriteLine(i + j); }
    }

    public class action
    {
        public string ActionType { get; set; }
        public void Run()
        {
            Console.WriteLine("我是跑!"); 
        }

        public void Eat()
        {
            Console.WriteLine("我是吃!"); 
        }
    }
}

最后各种反射方法

        /// <summary>
        /// 获取程序集
        /// </summary>
        /// <param name="assemblyResult"></param>
        /// <returns></returns>
        public static Assembly GetAssembly(AssemblyResult assemblyResult)
        {
            Assembly assembly = Assembly.Load(assemblyResult.AssemblyName);
            return assembly;
        }
        /// <summary>
        /// 获取类
        /// </summary>
        /// <param name="assembly"></param>
        /// <returns></returns>
        public static List<ClassInfo> GetClassNames(Assembly assembly)
        {
            //List<string> classNames = new List<string>();
            List<ClassInfo> classInfoList = new List<ClassInfo>();
            Type[] ts = assembly.GetTypes();
            foreach (Type t in ts)
            {
                ClassInfo classInfo = new ClassInfo();
                classInfo.ClassName = t.FullName;
                //classNames.Add(t.FullName);
                classInfoList.Add(classInfo);
            }
            return classInfoList;
        }
        /// <summary>
        /// 获取类下的所有方法
        /// </summary>
        /// <param name="assembly"></param>
        /// <param name="assemblyResult"></param>
        /// <returns></returns>
        public static void GetMethods(Assembly assembly, AssemblyResult assemblyResult)
        {
            for (int i = 0; i < assemblyResult.ClassInfos.Count; i++)
            {
                List<string> methodsList = new List<string>();
                //获取类
                Type ts = assembly.GetType(assemblyResult.ClassInfos[i].ClassName, false, true);
                //创建一个类的实例
                object obj = Activator.CreateInstance(ts);
                MethodInfo[] methods = ts.GetMethods();
                foreach (var item in methods)
                {
                    methodsList.Add(item.Name);
                    //反射调用类的方法
                    if (item.Name == "Add")
                    {
                        object[] num = new object[] { 1, 2 };
                        //参数一obj:对其调用方法或构造函数的对象,static可忽略。参数二:方法的参数列表object[] parameters
                        item.Invoke(obj, num);
                    }
                    else if (item.Name == "Show" || item.Name == "Say")
                    {
                        item.Invoke(obj, null);
                    }
                }
                assemblyResult.ClassInfos[i].Methods = methodsList;
            }
        }
        /// <summary>
        /// 获取类的属性
        /// </summary>
        /// <param name="assembly"></param>
        /// <param name="assemblyResult"></param>
        public static void GetProperties(Assembly assembly, AssemblyResult assemblyResult)
        {
            for (int i = 0; i < assemblyResult.ClassInfos.Count; i++)
            {
                List<string> propertiesList = new List<string>();
                //获取类
                Type ts = assembly.GetType(assemblyResult.ClassInfos[i].ClassName, false, true);
                //创建一个类的实例
                object obj = Activator.CreateInstance(ts);
                PropertyInfo[] properties = ts.GetProperties();
                foreach (var item in properties)
                {
                    propertiesList.Add(item.Name);
                    switch (item.Name)
                    {
                        case "Name":
                            item.SetValue(obj, "XiaoMing");
                            break;
                        case "Age":
                            item.SetValue(obj, 18);
                            break;
                        case "ActionType":
                            item.SetValue(obj, "");
                            break;
                        default:
                            break;
                    }
                    Console.WriteLine("我通过反射修改了属性{0}的值,现为{1}。", item.Name, item.GetValue(obj, null));
                }
                assemblyResult.ClassInfos[i].Properties = propertiesList;
            }
        }

最后主程序调用

        static void Main(string[] args)
        {
            AssemblyResult assemblyResult = new AssemblyResult("ClassLibrary1");
            Assembly assembly = GetAssembly(assemblyResult);
            assemblyResult.ClassInfos = GetClassNames(assembly);
            GetMethods(assembly, assemblyResult);
            GetProperties(assembly, assemblyResult);
            Console.ReadKey();
        }

注:

获取程序集的时候用了Assembly.Load()方法,如:AssemblyResult assemblyResult = new AssemblyResult("ClassLibrary1");

要在程序集头引用 using ClassLibrary1;

若以文件的方式获取程序集,用Assembly.LoadFile()或者Assembly.LoadFrom()

区别:

LoadFile:这个方法是从指定的文件来加载程序集,它是调用外部的API实现的加载方式,和上面Load,LoadFrom方法的不同之处是这个方法不会加载此程序集引用的其他程序集,也就是不会加载程序的依赖项。而同时也是不能加载相同标识的程序集的。

LoadFrom:

1.如果已加载一个具有相同标识的程序集,则即使指定了不同的路径,LoadFrom 仍返回已加载的程序集。

2.如果用 LoadFrom 加载一个程序集,随后加载上下文中的一个程序集尝试加载具有相同显示名称的程序集,则加载尝试将失败。对程序集进行反序列化时,可能发生这种情况。

3.LoadFrom只能用于加载不同标识的程序集, 也就是唯一的程序集, 不能用于加载标识相同但路径不同的程序集。

 


Type ts = assembly.GetType(assemblyResult.ClassInfos[i].ClassName, false, true);//注册类
object obj = Activator.CreateInstance(ts);//创建ts的实例对象
创建ts类的实例对象的时候会默认调用ts的无参构造函数,若ts类里有带参数的构造函数,那必须也写一个无参的构造函数,否则会报错

 

 

 

posted @ 2017-02-07 17:38  花生打代码会头痛  阅读(107)  评论(0)    收藏  举报