C#2008与.NET 3.5 高级程序设计读书笔记(16) 类型反射、晚期绑定和基于特性的编程

1.反射

在.NET中,反射(reflection)是一个运行库类型发现的过程.通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。

(1)命名空间

(2)一些在发射中经常用到的类

Assembly

Assembly类是可重用、无版本冲突并且可自我描述的公共语言运行库应用程序构造块。可以使用Assembly.LoadAssembly.LoadFrom方法动态地加载程序集。

Type

反射的中心是System.Type类。System.Type类是一个抽象类,代表公用类型系统中的一种类型。这个类使您能够查询类型名、类型中包含的模块和名称空间、以及该类型是一个数值类型还是一个引用类型。

System.Type类使您能够查询几乎所有与类型相关的属性,包括类型访问限定符、类型是否、类型的COM属性等等。

获取给定类型的Type引用有3种常用方式:
    ●使用 C# typeof 运算符。
        Type t = typeof(string);
    ●使用对象GetType()方法。
        string s = "grayworm";
        Type t = s.GetType();
    ●还可以调用Type类的静态方法GetType()。
        Type t = Type.GetType("System.String");

Activator

Activator类支持动态创建.NET程序集和COM对象。可以通过CreateComInstanceFromCreateInstanceCreateInstanceFromGetObject四个静态方法加载COM对象或者程序集,并能创建指定类型的实例。

Binder

Binder类是一个用于执行类型转换的绑定器,Type对象的InvokeMember方法接受Binder对象,这个对象描述了如何将传递给InvokeMember的参数转换成方法实际需要的类型。

Binder类是一个抽象类,要创建绑定器,需要重写方法BindToMethodBindToFieldSelectMehtodSelectPropertyChangeType

DefaultMemberAttribute

    DefaultMemberAttribute类用于类型并带有一个指明默认成员名称的字符串参数。能够通过InvokeMember调用默认成员,而不需要传递调用成员的名称。当需要绑定器但不需要特别的绑定行为时就可以使用它。

其它

还有一些对元素类型信息描述的类,ConstrutorInfo(构造函数)、MethodInfo(方法)、FieldInfo(字段)、PropertyInfo(属性)、EventInfo(事件)、MemberInfo(成员)、ParameterInfo(参数)。如果查询得到了具有任何类型信息的实例,就可以获得该类型中任意元素的类型信息,当然出于安全原因,不保证会得到程序集中的任何信息。

例子:

首先我们先建立一个类库工程MyDll,并新建一个类ReflectTest

代码
using System;

namespace MyDll
{
/**//// <summary>
/// ReflectTest 的摘要说明。
/// </summary>

//接口
public interface ITest
{
int add();

}

public class ReflectTest : ITest
{
public String Write;
private String Writec;

public int add()
{
return 10;
}

public String Writea
{
get { return Write;}
set { Write = value;}
}

private String Writeb
{
get { return Writec;}
set { Writec = value;}
}

//构造函数
public ReflectTest()
{
this.Write = "Write";
this.Writec = "Writec";
}

//有参构造函数
public ReflectTest(string str1,string str2)
{
this.Write = str1;
this.Writec = str2;
}

public string PrintString(string s)
{
return "这是一个实例方法" + s;
}

private string PrintString2()
{
return "这是一个私有方法";
}

public static string Print(string s)
{
return "这是一个静态方法," + s;
}

public string PrintNoPara()
{
return "您使用的是无参数方法";
}

public static string PrintData(string s)
{
return s;
}

public static string PrintData(string s1, string s2)
{
return s1+s2;
}



}
}

编译后得到MyDll.dll文件,应用反射

代码
using System;
using System.Reflection;

namespace cmdText
{
/**//// <summary>
/// 说明:反射学习
/// 程序:寻梦E.net
/// </summary>
public class Reflect2
{

delegate string TestDelegate(string value1);

public static void Main(string[] args)
{
Assembly ass
= null ;
Type type
= null ;
object obj = null;

string assemblyName = "MyDll";
string className = "MyDll.ReflectTest";

try
{
//以下三种方法都可以
//ass = Assembly.LoadFile(System.Environment.CurrentDirectory+"/MyDll.dll");
//ass = Assembly.LoadFrom(System.Environment.CurrentDirectory+"/MyDll.dll");
ass = Assembly.Load(assemblyName);

}
catch
{
Console.Write(
"无法找到程序集!");
return;

}
//获取类型
type = ass.GetType(className);
//type = Type.GetType(className);//效果同上
//生成一个类实例,无参构造函数
obj = ass.CreateInstance(className);
//obj = Activator.CreateInstance(type);//效果同上


//**************************方法调用*************************************
//反射实例方法

Console.WriteLine(
"*******方法调用**************************************");
MethodInfo method
= type.GetMethod("PrintString");
string s = (string)method.Invoke(obj,new string[]{"寻梦E.net"});
Console.WriteLine(s);

//反射私有方法
method = type.GetMethod("PrintString2",BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
s
= (string)method.Invoke(obj,null);
Console.WriteLine(s);

//反射静态方法
method = type.GetMethod("Print");
s
= (string)method.Invoke(null,new string[]{"寻梦E.net"});
Console.WriteLine(s);

//反射无参方法
method = type.GetMethod("PrintNoPara");
s
= (string)method.Invoke(obj,null);
Console.WriteLine(s);

//反射重载了的静态方法
Type[] objParam = {typeof(string),typeof(string)};
method
= type.GetMethod("PrintData",objParam );
s
= (string)method.Invoke(null,new object[]{"hello!"," 寻梦E.net"});
Console.WriteLine(s);

Console.WriteLine(
"*******属性,域的赋值与访问***********************");


//*****************属性,域的赋值与访问***************************************
//公有属性
PropertyInfo pi1 = type.GetProperty("Writea");
pi1.SetValue(obj,
"公有属性:Writea", null);
Console.WriteLine(pi1.GetValue(obj,
null));

//私有属性
PropertyInfo pi2 = type.GetProperty("Writeb", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
pi2.SetValue(obj,
"私有属性:Writeb", null);
Console.WriteLine(pi2.GetValue(obj,
null));

//
FieldInfo fi1 = type.GetField("Write");
Console.WriteLine(fi1.GetValue(obj));


Console.WriteLine(
"*******类型,模块,方法,构造函数等信息的获取*****");




//******************类型,模块,方法,构造函数等信息的获取******************************************

//有参构造函数实例化
//string[] classParams = {"lsm","sky"};
//object obj2 = Activator.CreateInstance(type,classParams);

foreach(Type t in ass.GetTypes())
{
Console.WriteLine(
"类型:"+t.Name );
}

foreach(Module m in ass.GetModules())
{
Console.WriteLine(
"模块:"+m.Name);
}

MethodInfo[] methods
= type.GetMethods();
foreach (MethodInfo m in methods)
{
Console.WriteLine(
"方法"+m.Name); //显示所有的共有方法
}

FieldInfo[] fields
= type.GetFields();
foreach (FieldInfo f in fields)
{
Console.WriteLine(
"字段信息:"+f.Name);
}

PropertyInfo[] propertys
= type.GetProperties();
foreach( PropertyInfo p in propertys)
{
Console.WriteLine(
"属性:"+p.Name);
}

ConstructorInfo[] ci1
= type.GetConstructors();
foreach (ConstructorInfo ci in ci1)
{
Console.WriteLine(
"构造函数:"+ci.ToString()); //获得构造函数的形式

}

//*******************接口***************************************

Console.WriteLine(
"*******接口*****************************************");

MyDll.ITest obj1
= (MyDll.ITest)ass.CreateInstance(className);//这里必须是实现接口的类名,因为接口不能实例化
//MyDll.ReflectTest obj2= (MyDll.ReflectTest)ass.CreateInstance(className);
//典型的工厂模式
int i = obj1.add();
Console.WriteLine(i);


//*****************委托*******************************************

TestDelegate myDelegate
= (TestDelegate)Delegate.CreateDelegate(typeof(TestDelegate), obj, "PrintString");
//动态创建委托的简单例子
Console.WriteLine(myDelegate(" 动态调用委托"));


//*****************获得解决方案的所有Assembly********************

Assembly[] assemblys
= AppDomain.CurrentDomain.GetAssemblies();
//遍历显示每个Assembly的名字
foreach (object var in assemblys)
{
Console.WriteLine(
"所有的Assembly的名字:"+var.ToString());
}


Console.Read();



}


}
}

 2.Attribute(特性)

MADN的定义为:公共语言运行时允许添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型、字段、方法和属性等。Attributes和Microsoft .NET Framework文件的元数据(metadata)保存在一起,可以用来向运行时描述你的代码,或者在程序运行的时候影响应用程序的行为。

Attribute就是一种“附着物”——就像牡蛎吸附在船底或礁石上一样。这些附着物的作用是为它们的附着体追加上一些额外的信息(这些信息就保存在附着物的体内)——比如“这个类是我写的”或者“这个函数以前出过问题”等等。

你可能会问:这跟注释有什么区别呢?

当然有区别啦!注释是对程序源代码的一种说明,主要目的是给人看的,在程序被编译的时候会被编译器所丢弃,因此,它丝毫不会影响到程序的执行。而Attribute是程序代码的一部分,不但不会被编译器丢弃,而且还会被编译器编译进程序集(Assembly)的元数据(Metadata)里,在程序运行的时候,你随时可以从元数据里提取出这些附加信息来决策程序的运行。

例子:

自定义Attribute类:VersionAttribute

代码
[AttributeUsage(AttributeTargets.Class)]
public class VersionAttribute : Attribute
{
public string Name { get; set; }
public string Date { get; set; }
public string Describtion { get; set; }
}

使用自定义Attribute的Class:

[Version(Name = "hyddd", Date = "2009-07-20", Describtion = "hyddd's class")]
public class MyCode
{
//...
}

上面这个Class中的Attribute一般会被如何使用呢?

代码
class Program
{
static void Main(string[] args)
{
var info
= typeof(MyCode);
var classAttribute
= (VersionAttribute)Attribute.GetCustomAttribute(info, typeof(VersionAttribute));
Console.WriteLine(classAttribute.Name);
Console.WriteLine(classAttribute.Date);
Console.WriteLine(classAttribute.Describtion);
}
}
原文地址:https://www.cnblogs.com/engine1984/p/1793307.html