反射和特性
一.反射
1.元数据和反射
(1)程序是用来处理数据的,文本和特性都是数据,而我们程序本身(类的定义和BLC中的类)这些也是数据。
(2)有关程序及其类型的数据被称为元数据(metadata),它们保存在程序的程序集中。 程序在运行时,可以查看其它程序集或其本身的元数据。
(3)一个运行的程序查看本身的元数据或者其他程序集的元数据的行为叫做反射。
2.使用type类型进行反射
上例子
namespace _014_反射和特性 { class MyClass { private int id; private int age; public int number; public string Name { get; set; } public string Name2 { get; set; } public string Name3 { get; set; } public void Test1() { } public void Test2() { } } } namespace _014_反射和特性 { class Program { static void Main(string[] args) { //每一个类对应一个type对象,这个type对象存储了这个类 有哪些方法跟哪些数据 哪些成员 MyClass my = new MyClass();//一个类中的数据 是存储在对象中的, 但是type对象只存储类的成员 Type type = my.GetType();//通过对象获取这个对象所属类 的Type对象 Console.WriteLine(type.Name);//获取类的名字 Console.WriteLine(type.Namespace);//获取所在的命名空间 Console.WriteLine(type.Assembly); FieldInfo[] array = type.GetFields();//只能获取public 字段 foreach (FieldInfo info in array) { Console.Write(info.Name + " "); } PropertyInfo[] array2 = type.GetProperties(); foreach (PropertyInfo info in array2) { Console.Write(info.Name + " "); } MethodInfo[] array3 = type.GetMethods(); foreach (MethodInfo info in array3) { Console.Write(info.Name + " "); } // 通过type对象可以获取它对应的类的所有成员(public)
}
}
2.Assembly获取程序集
例
MyClass my = new MyClass(); Assembly assem = my.GetType().Assembly;//通过类的type对象获取它所在的程序集 Assembly Console.WriteLine(assem.FullName); Type[] types = assem.GetTypes(); foreach (var type in types) { Console.WriteLine(type); } Console.ReadKey();
还有
1,Assembly assembly1 = Assembly.Load("SomeAssembly");根据程序集的名字加载程序集,它会在本地目录和全局程序集缓存目录查找符合名字的程序集。
2,Assembly assembly2 = Assembly.LoadFrom(@"c:\xx\xx\xx\SomeAssembly.dll")//这里的参数是程序集的完整路径名,它不会在其他位置搜索。
二.特性
1.Obsolete特性(添加至方法前面)
一个程序可能在其生命周期中经历多次发布,而且很可能延续多年。在程序生命周期的后半部分,程序员经常需要编写类似功能的新方法替换老方法。处于多种原因,你可能不再使用哪些调用过时的旧方法的老代码。而只想用新编写的代码调用新方法。旧的方法不能删除,因为有些旧代码也使用的旧方法,那么如何提示程序员使用新代码呢?可以使用Obsolete特性将程序结构标注为过期的,并且在代码编译时,显示有用的警告信息。
[Obsolete("Use method SuperPrintOut")] //将特性应用到方法 static void PrintOut(string str){ Console.WriteLine(str); } [Obsolete("Use method SuperPrintOut",true)]//这个特性的第二个参数表示是是否应该标记为错误,而不仅仅是警告。 static void PrintOut(string str){ Console.WriteLine(str); }
2.Conditional特性(添加至方法前面)
Conditional特性允许我们包括或取消特定方法的所有调用。虽然方法的调用是取消了但是方法还是会进行编译到程序集。
//#define DoTrace//如果想调用TraceMessage这个方法这里需要定义一个宏 class Program{ [Conditional("DoTrace")] //括号中的字符串是随便输入的 static void TraceMessage(string str){ Console.WriteLine(str); } static void Main(){ TraceMessage("Start of Main"); Console.WriteLine("Doing work in Main.") TraceMessage("End of Main"); }
3.调用者信息特性(添加至参数前面)
调用者信息特性可以访问文件路径,代码行数,调用成员的名称等源代码信息。(感觉这个特性没什么卵用)
public static void PrintOut(string message,[CallerFilePath] string filename="",[CallerLineNumber]int lineNumber = 0,
[CallerMemberName]string callingMember="")
{ Console.WriteLine("Message:"+message); Console.WriteLine("Line :"+lineNumber); Console.WriteLine("Called from:"+callingMember); Console.WriteLine("Message :"+message); }
4.DebuggerStepThrough特性
我们在单步调试代码的时候,有的方法知道肯定不会出错我们可以进行跳过。
class Program{ int _x=1; int X{ get{return _x;}; [DebuggerStepThrough]//可以跳过debugger的单步调试 set{ _x=_x*2; _x+=value; } } public int Y{get;set;} [DebuggerStepThrough] void IncrementFields(){ X++; Y++; }
所以特性(attribute)是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。 将应用了特性的程序结构叫做目标 设计用来获取和使用元数据的程序(对象浏览器)叫做特性的消费者 .NET预定了很多特性,我们也可以声明自定义特性