当前位置:编程学习 > C#/ASP.NET >>

关于c#中的反射和定制特性

在c#中反射都有哪些具体应用?关于定制特性有哪些用途? --------------------编程问答-------------------- 反射在工厂模式的时候很有用的 --------------------编程问答-------------------- 关于特性,请参见这里:
http://blog.csai.cn/user1/16236/archives/2009/39771.html --------------------编程问答-------------------- C#反射浅析
首先了解C#反射的概念,反射是一个运行库类型发现的过程。通过反射可以得到一个给定程序集所包含的所有类型的列表,
这个列表包括给定类型中定义的方法、字段、属性和事件。也可以动态的发现一组给定类支持的借口、方法的参数和其他
相关信息如基类、命名空间、数据清单等。

C#反射命名空间详细介绍:

1.System.Reflection命名空间内的各类型

(1) Assembly通过它可以加载、了解和操纵一个程序集

(2) AssemblyName 通过它可以找到大量隐藏在程序集的身份中的信息,如版本信息、区域信息等

(3) EventInfo  事件的信息

(4) FieldInfo  字段的信息

(5) MethodInfo  方法的信息

(6) ParameterInfo  参数的信息

(7) PropertyInfo  属性的信息

(8) MemberInfo  是抽象基类,为  EventInfo、FieldInfo 、MethodInfo、PropertyInfo等类型定义了公共的行为。

(9) Module 用来访问带有多文件程序集的给定模块  

2.System.Type类 

System.Type支持的成员可以分为这样几类

(1) Is***   用来检查一个类型的元数据,如IsAbstract、IsClass、IsValueType等等

(2) Get*** 用来从类型得到指定项目,如GetEvent()得到类型的一个指定的事件(EventInfo)。 
另外,这些方法都有一个单数版本和一个复数版本。如GetEvent()对应有一个复数版本GetEvents(),
该方法返回一个相关的EventInfo数组。

(3) FindMembers()   根据查询条件返回一个MemberInfo类型的数组

(4)GetType()  该静态方法根据一个字符串名称返回一个Type实例

(5)InvokeMember()  对给定项目进行晚期绑定

3.得到一个Type类型实例的三种方法

因为Type是一个抽象类,所以不能直接使用new关键字创建一个Type对象

(1)使用System.Object.GetType()

Person pe=new Person();    //---------定义pe为person类的一个对象   
Type t=pe.GetType();  

(2)使用System.Type.GetType()静态方法,参数为类型的完全限定名

Type t=Type.GetType("Entity.Person"); 该方法被重载,允许指定两个布尔类型的参数,一个用来控制当前类型不能找到时是否抛出异常,

另一个用来指示是否区分字符串大小写 

Type t=Type.GetType("Entity.Person",false,true); 注意到传入的字符串并没有包含类型所在的程序集信息,此时该类型便被认为是定义在当前执行的程序集中的。

要得到一个外部私有程序集的类型元数据时,字符串参数必须使用类型完全限定名加上类型所在程序集的友好名字

Type t=Type.GetType("Entity.Person","Entity");  //------"Entity"即为类型所在程序集的友好名字  嵌套类型:传入的字符串可以指定一个+标记来表示一个嵌套类型,

如希望得到一个嵌套在person类中的枚举类型City的类型信息,则可以这样

Type t=Type.GetType("Entity.person+City"); 

(3)使用typeof运算符

Type  t=typeof(person); 三种方法的比较:

使用第一种方法必须先建立一个实例,而后两种方法不必先建立实例。但使用typeof运算符仍然需要知道类型的编译时信息,

而使用System.Type.GetType()静态方法不需要知道类型的编译时信息,所以是首选方法。

一个最简单的C#反射实例,首先编写类库如下:
namespace ReflectionTest
{  
   public class WriteTest  
   {  
       //带参数的公共方法
    public void WriteString(string s, int i)  
    {  
       Console.WriteLine("WriteString:" + s + i.ToString());  
    }   
    //带一个参数的静态方法
    public static void StaticWriteString(string s)
    { 
          Console.WriteLine("StaticWriteString:" + s); 
    }  
    //不带参数的静态方法
    public static void NoneParaWriteString() 
    { 
         Console.WriteLine("NoParaWriteString"); 
    }  
   } 


class TestApp
{  
   public static void Main()  
   {  
    Assembly ass;  
    Type type;  
    Object obj;   
    //用来测试静态方法
    Object any = new Object();   
    //指定类库文件必须使用绝对路径,不能使用相对路径
    ass = Assembly.LoadFile(@"D:\Source Code\00.C#Sudy\01.Reflection\01\ReflectTest.dll");  
    //命名空间和类的名字必须一起指定  
    type = ass.GetType("ReflectionTest.WriteTest");  
    
    /**//*example1---------*/  
    MethodInfo method = type.GetMethod("WriteString");   
    string test = "test";  
    int i = 1;   
    Object[] parametors = new Object[]{test,i};   
    //在例子1种必须实例化反射要反射的类,因为要使用的方法并不是静态方法。
    //创建对象实例
    obj = ass.CreateInstance("ReflectionTest.WriteTest");      
    //执行带参数的公共方法
    method.Invoke(obj, parametors);  
    //method.Invoke(any, parametors);//异常:必须实例化反射要反射的类,因为要使用的方法并不是静态方法。
    
    /**//*example2----------*/   
    method = type.GetMethod("StaticWriteString");  
    method.Invoke(null, new string[] { "test"});  //第一个参数忽略
    //对于第一个参数是无视的,也就是我们写什么都不会被调用,
    //即使我们随便new了一个any这样的Object,当然这种写法是不推荐的。
    //但是对应在例子1种我们如果Invoke的时候用了类型不一致的实例来做为参数的话,将会导致一个运行时的错误。
    method.Invoke(obj, new string[] { "test"});
    method.Invoke(any, new string[] { "test"});
    
    /**//*example3-----------*/  
    method = type.GetMethod("NoneParaWriteString"); //调用无参数静态方法的例子,这时候两个参数我们都不需要指定,用null就可以了。s  
    method.Invoke(null, null); 
   } 
}  


    从上面的总结中可以看出,对于外部调用的动态库应用反射时要用到Assembly.LoadFile(),然后才是获取类型、执行方法等;
当用反射创建当前程序集中对象实例或执行某个类下静态方法时只需通过Type.GetType("类的完整名")。
--------------------编程问答-------------------- 反射提供了封装程序集、模块和类型的对象(Type 类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了属性,可以利用反射对它们进行访问。有关更多信息 
反射概述 

公共语言运行库加载器管理应用程序域,这些域在拥有相同应用程序范围的对象周围形成了确定边界。这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。 

程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。反射通常具有以下用途: 

使用 Assembly 定义和加载程序集,加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。 

使用 Module 了解如下的类似信息:包含模块的程序集以及模块中的类等。您还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。 

使用 ConstructorInfo 了解以下信息:构造函数的名称、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。使用 Type 的 GetConstructors 或 GetConstructor 方法来调用特定的构造函数。 

使用 MethodInfo 了解以下信息:方法的名称、返回类型、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。使用 Type 的 GetMethods 或 GetMethod 方法来调用特定的方法。 

使用 FieldInfo 了解以下信息:字段的名称、访问修饰符(如 public 或 private)和实现详细信息(如 static)等;并获取或设置字段值。 

使用 EventInfo 来了解如下的类似信息:事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。 

使用 PropertyInfo 来了解如下的类似信息:属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。 

使用 ParameterInfo 来了解如下的类似信息:参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等。 

当您在一个应用程序域的仅反射上下文中工作时,请使用 CustomAttributeData 来了解有关自定义属性的信息。使用 CustomAttributeData,您不必创建属性的实例就可以检查它们。 

System.Reflection.Emit 命名空间的类提供了一种特殊形式的反射,使您能够在运行时构造类型。 

反射也可用于创建称作类型浏览器的应用程序,它使用户能够选择类型,然后查看有关选定类型的信息。 

反射还有其他一些用途。JScript 等语言编译器使用反射来构造符号表。System.Runtime.Serialization 命名空间中的类使用反射来访问数据并确定要持久保存的字段。System.Runtime.Remoting 命名空间中的类通过序列化来间接地使用反射。 
--------------------编程问答-------------------- 看了回复,我还是不太懂。。。郁闷 --------------------编程问答-------------------- mark --------------------编程问答-------------------- 还基本上! --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 还是不懂,唉,没人手把手教还真难搞懂啊 --------------------编程问答-------------------- 自己动手尝试写一个可以处理任意类型的组件就能掌握许多反射的技术.
比如写一个简单的C#对象序列化为json的组件. --------------------编程问答-------------------- 反射能让你自己管理类型,用程序掌控系统架构,如果你没用到过,说明你编的程序还不够复杂 --------------------编程问答-------------------- 反射我也不会 --------------------编程问答-------------------- 关于定制特性Attribute,它被施加到类型或者方法上,DllImport]施加到MessageBox函数上, [Conditional]施加到DisplayRuntimeMessage方法和DisplayDebugMessage方法,[Obsolete]施加到DisplayDebugMessage方法上。
如: 
[DllImport("User32.dll")]//从中User32.dll导出API函数MessageBox
  public static extern int MessageBox(int hParent, string Message, string Caption, int Type);
  [Conditional("DEBUG")]//指定此函数正在debug版本运行,release下当成没有。有点代替c++中的#ifdef _DEBUG #else 的意思。 
private static void DisplayRunningMessage() { Console.WriteLine("开始运行Main子程序。当前时间是" + DateTime.Now); }
[Obsolete("Don't use Old method, use New method", true)]  //编译此函数时会出现相关的报警信息
    static void Old( ) { }
--------------------编程问答-------------------- 看了一下还是不懂什么是反射什么是特性。。很抽象,很难理解。望有经验的介绍。
补充:.NET技术 ,  .NET技术前瞻
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,