C#反射

反射是在程序运行时,发现和使用类型、成员的能力。

.NET上的语言编译后生产的是中间代码,中间代码保留了类型、成员自身的信息。

获取类型信息

System.Type表示类型信息。

通过obj.GetType()获取实例成员的类型信息。

通过typeof(类型名称)获取类型的System.Type

反射获取类型全名

int i = 10;
Console.WriteLine(i.GetType().FullName);//System.Int32

反射相关的类型

反射相关的类型大多都在System.Reflection命名空间。

Assembly表示程序集。通过该类,可以获取程序集的定义的所有类型,内嵌资源和特征等。

Module表示模块。一般一个程序集只有一个模块。

MemberInfo表示成员信息,是成员的基类。通过该类,可以获取成员的名称,特征等。

MethodBase表示方法的基类。可以获取方法的参数,返回值等。

ParameterInfo表示参数信息。可以获取参数类型,是否为ref,out等。

ConstratorInfo表示构造函数。通过构造函数,可以创建类型。

FieldInfo表示字段。通过字段,可以读取字段。

PropertyInfo表示属性。通过属性,可以获取读写方法,可以读写属性。

MethodInfo表示方法。通过方法,可以调用方法。

EventInfo表示事件。通过事件,可以获取注册注销方法,可以注册注销事件。

类型信息类型的基本成员

public class Type
{
    //获取类型的简短名称
    public string Name{get;}
    //获取类型的全名
    public string FullName{get;}
    //此类型所在的程序及
    public Assembly Assembly{get;}
    //判断类型是否是值类型
    public bool IsValueType{get;}
    //判断类型是否是引用类型
    public bool IsReferenceType{get;}
    //判断类型是否是接口
    public bool IsInterface{get;}
    //获取类型基类的类型
    public Type BaseType{get;}
    //获取一个类型的成员
    public MemberInfo GetMember(string name);
    //获取一个类型的方法
    public MethodInfo GetMethod(string name);
 }

通过System.Type可以获取包括定义信息,成员信息等。

反射实例

object obj = "ok";

PropertyInfo lengthProperty = obj.GetType().GetProperty("Length");
int length = (int)lengthProperty.GetValue(obj,null);

反射的作用

运行时使用类型

运行时可以知道类型,成员信息。

Visual Studio的对象浏览器也是通过反射实现的。

使用非公开的类型和成员

可见性修饰符限制了访问范围,反射可以打破。

使用特征

特征只有被反射才有作用。

使用类型未知的成员

反射可以使用任意类型,而不需要事先知道。

举例来说,将任意一个类的所有属性转换为JSON格式的字符串。没有反射,不知道类型的属性信息。

字节码

反射可以发现类型,成员,但是反射得不到方法的代码。

通过Mono.Cecil包,可以得到方法的字节码并加以修改。

插件

在C#中如果要实现插件,接口配合反射是最佳的方法。

公共程序集中定义插件的借口。

插件应用公共程序及,实现接口,完成插件功能。

主程序中加载插件目录下的程序集,找到所有实现插件接口的类型,并初始化。

公用程序集

public class PluginContext
{
    //包含程序提供给接口的数据和方法,比如支持插件添加菜单项,操作文本等。是宿主开放给插件的功能
}
public interface IPlugin
{
    void Init(PluginContext context);
    //额外的插件方法
}

插件程序

public class MyPlugin
{
    public void Init(PluginContext context)
    {
        Console.WriteLine("init ok");
    }
}

主程序

扫描并初始化插件

     public List<IPlugin> GetPlugins(PluginContext context)
        {
            List<IPlugin> plugins = new List<IPlugin>();
            foreach (string file in Directory.GetFiles("plugins"))
            {
                try
                {
                    Assembly assembly = Assembly.LoadFile(file);

                    foreach (var type in assembly.GetTypes())
                    {
                        if (type.IsClass && !type.IsAbstract &&
                            typeof(IPlugin).IsAssignableFrom(type))
                        {
                            try
                            {
                                IPlugin plugin = (IPlugin)Activator.CreateInstance(type);
                                plugin.Init(context);
                                plugins.Add(plugin);
                            }
                            catch (Exception)
                            {

                            }
                        }
                    }
                }
                catch (IOException)
                {

                }
                catch (BadImageFormatException)
                {

                }
            }

            return plugins;
        }

Visual Studio就是一个典型的插件化的程序。