.NET中如何实现反射?

在.NET中,为我们提供了丰富的可以用来实现反射的类型,这些类型大多数都定义在System.Reflection命名空间之下,例如Assembly、Module等。利用这些类型,我们就可以方便地动态加载程序集、模块、类型、方法和字段等元素。

下面我们来看一个使用示例,首先是创建一个程序集SimpleAssembly,其中有一个类为SimpleClass:.

[Serializable]
public class SimpleClass
{
    private String _MyString;
    public SimpleClass(String mystring)
    {
        _MyString = mystring;
    }

    public override string ToString()
    {
        return _MyString;
    }

    static void Main(string[] args)
    {
        Console.WriteLine("简单程序集");
        Console.Read();
    }
}

其次是对程序集中的模块进行分析,分别利用反射对程序集、模块和类进行分析:

public class AnalyseHelper
{
    /// <summary>
    /// 分析程序集
    /// </summary>
    public static void AnalyzeAssembly(Assembly assembly)
    {
        Console.WriteLine("程序集名字:" + assembly.FullName);
        Console.WriteLine("程序集位置:" + assembly.Location);
        Console.WriteLine("程序集是否在GAC中:" +
                    assembly.GlobalAssemblyCache.ToString());
        Console.WriteLine("包含程序集的模块名" +
            assembly.ManifestModule.Name);
        Console.WriteLine("运行程序集需要的CLR版本:" +
            assembly.ImageRuntimeVersion);
        Console.WriteLine("现在开始分析程序集中的模块");
        Module[] modules = assembly.GetModules();
        foreach (Module module in modules)
        {
            AnalyzeModule(module);
        }
    }

    /// <summary>
    /// 分析模块
    /// </summary>
    public static void AnalyzeModule(Module module)
    {
        Console.WriteLine("模块名:" + module.Name);
        Console.WriteLine("模块的UUID:" + module.ModuleVersionId);
        Console.WriteLine("开始分析模块下的类型");
        Type[] types = module.GetTypes();
        foreach (Type type in types)
        {
            AnalyzeType(type);
        }
    }

    /// <summary>
    /// 分析类型
    /// </summary>
    public static void AnalyzeType(Type type)
    {
        Console.WriteLine("类型名字:" + type.Name);
        Console.WriteLine("类型的类别是:" + type.Attributes);
        if (type.BaseType != null)
            Console.WriteLine("类型的基类是:" + type.BaseType.Name);
        Console.WriteLine("类型的GUID是:" + type.GUID);
        //设置感兴趣的类型成员
        BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
        //分析成员
        FieldInfo[] fields = type.GetFields(flags);
        if (fields.Length > 0)
        {
            //Console.WriteLine("开始分析类型的成员");
            foreach (FieldInfo field in fields)
            {
                // 分析成员
            }
        }
        //分析包含的方法
        MethodInfo[] methods = type.GetMethods(flags);
        if (methods.Length > 0)
        {
            //Console.WriteLine("开始分析类型的方法");
            foreach (MethodInfo method in methods)
            {
                // 分析方法
            }
        }
        //分析属性
        PropertyInfo[] properties = type.GetProperties(flags);
        if (properties.Length > 0)
        {
            //Console.WriteLine("开始分析类型的属性");
            foreach (PropertyInfo property in properties)
            {
                // 分析属性
            }
        }
    }
}

最后编写入口方法来尝试分析一个具体的程序集:

[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public class Program
{
    public static void Main(string[] args)
    {
        Assembly assembly = Assembly.LoadFrom(@"..\..\..\SimpleAssembly\bin\Debug\SimpleAssembly.exe");
        AnalyseHelper.AnalyzeAssembly(assembly);

        // 创建一个程序集中的类型的对象
        Console.WriteLine("利用反射创建对象");
        string[] paras = { "测试一下反射效果" };
        object obj = assembly.CreateInstance(assembly.GetModules()[0].GetTypes()[0].ToString(), true, BindingFlags.CreateInstance, null, paras, null, null);
        Console.WriteLine(obj);

        Console.ReadKey();
    }
}

上面的代码按照 程序集->模块->类型 三个层次的顺序来动态分析一个程序集,当然还可以继续递归类型内部的成员,最后通过CreateInstance方法来动态创建了一个类型,这些都是反射经常被用来完成的功能,执行结果如下图所示:

.NET中如何实现反射?