×

.NET技术----反射

Kalet Kalet 发表于2009-03-20 12:00:14 浏览291 评论0

抢沙发发表评论

1、什么是反射
反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等,。System.reflection命名空间包含的几个类,允许你反射(解析)这些元数据表的代码
.NET技术----反射
和反射相关的命名空间(我们就是通过这几个命名空间访问反射信息):

System.Reflection.MemberInfo

System.Reflection.EventInfo

System.Reflection.FieldInfo

System.Reflection.MethodBase

System.Reflection.ConstructorInfo

System.Reflection.MethodInfo

System.Reflection.PropertyInfo

System.Type

System.Reflection.Assembly 

       Reflection,中文翻译为反射。反射是种机制,可以获得一些元数据,可以检查当时正在运行的其他代码,还可以得到一些类的信息。
反射命名空间(System.Reflection)中的类以及 System.Type,您可以获取有关已加载的程序集和在其中定义的类型(如Class、Infterface和值类型等)的信息。您也可以使用反射在运行时创建类型实例,然后调用和访问这些实例。

2、运行期得到类型信息有什么用
反射的作用:

1. 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现 有对象中获取类型

2. 应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。

3. 反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能

    有人也许疑问,既然在开发时就能够写好代码,干嘛还放到运行期去做,不光繁琐,而且效率也受影响。
这就是个见仁见智的问题了,就跟早绑定和晚绑定一样,应用到不同的场合。有的人反对晚绑定,理由是损耗效率,但是很多人在享受虚函数带来的好处的时侯还没有意识到他已经用上了晚绑定。这个问题说开去,不是三言两语能讲清楚的,所以就点到为止了。
    我的看法是,晚绑定能够带来很多设计上的便利,合适的使用能够大大提高程序的复用性和灵活性,但是任何东西都有两面性,使用的时侯,需要再三衡量。


接着说,运行期得到类型信息到底有什么用呢?
还是举个例子来说明,很多软件开发者喜欢在自己的软件中留下一些接口,其他人可以编写一些插件来扩充软件的功能,比如我有一个媒体播放器,我希望以后可以很方便的扩展识别的格式,那么我声明一个接口:
public interface IMediaFormat
{
string Extension {get;}
Decoder GetDecoder();
}
这个接口中包含一个Extension属性,这个属性返回支持的扩展名,另一个方法返回一个解码器的对象(这里我假设了一个Decoder的类,这个类提供把文件流解码的功能,扩展插件可以派生之),通过解码器对象我就可以解释文件流。
 那么我规定所有的解码插件都必须派生一个解码器,并且实现这个接口,在GetDecoder方法中返回解码器对象,并且将其类型的名称配置到我的配置文件里面。
 这样的话,我就不需要在开发播放器的时侯知道将来扩展的格式的类型,只需要从配置文件中获取现在所有解码器的类型名称,而动态的创建媒体格式的对象,将其转换为IMediaFormat接口来使用。
 
 这就是一个反射的典型应用。

3.反射用法



  • 使用 Assembly 定义和加载程序集,加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。
  • 使用 Module 了解如下的类似信息:包含模块的程序集以及模块中的类等。您还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
  • 使用 ConstructorInfo 了解如下的类似信息:构造函数的名称、参数、访问修饰符(如 publicprivate)和实现详细信息(如 abstractvirtual)等。使用 TypeGetConstructorsGetConstructor 方法来调用特定的构造函数。
  • 使用 MethodInfo 来了解如下的类似信息:方法的名称、返回类型、参数、访问修饰符(如 publicprivate)和实现详细信息(如 abstractvirtual)等。使用 TypeGetMethodsGetMethod 方法来调用特定的方法。
  • 使用 FieldInfo 来了解如下的类似信息:字段的名称、访问修饰符(如 publicprivate)和实现详细信息(如 static)等;并获取或设置字段值。
  • 使用 EventInfo 来了解如下的类似信息:事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。
  • 使用 PropertyInfo 来了解如下的类似信息:属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。
  • 使用 ParameterInfo 来了解如下的类似信息:参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等。

//获取类型信息
Type t = Type.GetType("NameSpace.Classname");
//构造器的参数
object[] constuctParms = new object[]{"timmy"};
//根据类型创建对象
object dObj = Activator.CreateInstance(t,constuctParms);
//获取方法的信息
MethodInfo method = t.GetMethod("GetValue");
//调用方法的一些标志位,这里的含义是Public并且是实例方法,这也是默认的值
BindingFlags flag = BindingFlags.Public | BindingFlags.Instance;
//GetValue方法的参数
object[] parameters = new object[]{"Hello"};
//调用方法,用一个object接收返回值
object returnValue = method.Invoke(dObj,flag,Type.DefaultBinder,parameters,null);


例:
 public class TestClass
    {
        public string _value;
        public string petName;.NET技术----反射
        public string password;


        public string PetName
        {
            get { return this.petName; }
            set { this.petName = value; }
        }
                                      
        public string Password
        {
            get { return this.password; }
            set { this.password = value; }
        }



        public TestClass()
        {
        }
        public TestClass(string value)
        {
            _value = value;
        }


        public string GetValue(string prefix)
        {
            if (_value == null)
                return "NULL";
            else
                return prefix + " : " + _value;
        }


        public string Value
        {
            set
            {
                _value = value;
            }
            get
            {
                if (_value == null)
                    return "NULL";
                else
                    return _value;
            }
        }
    }

获取信息:
 System.Reflection.MemberInfo info = typeof(TestClass);
    object[] attributes = info.GetCustomAttributes(true);
    for (int i = 0; i < attributes.Length; i ++)
    {
          Response.Write(attributes[i]);
    }

System.Type 常用的方法和属性
Assembly                                   获取类所属的程序集
Attributes                                   获取与类型相关的属性
FullName                                   获取数据类型完全限定名
IsClass                                        判断当前类是否为类的类型
IsInterface
IsAbstract
GetEvents()                                  获取事件列表
GetMember()                              获取类型的指定成员
GetMembers()
GetProperty()                              获取类型指定的属性
GetPropertys()
GetMethods()                              获取所有的方法
......   
反射的性能:

使用反射来调用类型或者触发方法,或者访问一个字段或者属性时clr 需 要做更多的工作:校验参数,检查权限等等,所以速度是非常慢的。所以尽量不要使用反射进行编程,对于打算编写一个动态构造类型(晚绑定)的应用程序,可以采取以下的几种方式进行代替:

1. 通过类的继承关系。让该类型从一个编译时可知的基础类型派生出来,在运行时生成该类 型的一个实例,将对其的引用放到其基础类型的一个变量中,然后调用该基础类型的虚方法。

2. 通过接口实现。在运行时,构建该类型的一个实例,将对其的引用放到其接口类型的一个变量中,然后调用该接口定义的虚方法。

3.通过委托实现。让该类型实现一个方法,其名称和原型都与一个在编译时就已知的委托相符。在运行时先构造该类型的实例,然后在用该方法的对象及名称构造出该委托的实例,接着通过委托调用你想要的方法。这个方法相对与前面两个方法所作的工作要多一些,效率更低一些 

其实够我们研究的,这里写的只是简单应用,MSDN是开发的必看资料,只要我们把MSDN理解了,那就不用说啦。。。。。。。。。。。。.NET技术----反射



群贤毕至

访客