.NET反射、委托技术与设计模式

转自:http://hi.baidu.com/nanashitou/blog/item/ad7346eed769ffffb2fb958a.html

1 反射技术与设计模式
        反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及构造函数等。还可以获得每个成员的名称、限定符和参数等。有了反射,即可对每一个类型了如指掌。如果获得了构造函数的信息,即可直接创建对象,即使这个对象的类型在编译时还不知道。

1.1 .NET可执行应用程序结构
        程序代码在编译后生成可执行的应用,我们首先要了解这种可执行应用程序的结构。
        应用程序结构分为应用程序域—程序集—模块—类型—成员几个层次,公共语言运行库加载器管理应用程序域,这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。
        程序集包含模块,而模块包含类型,类型又包含成员,反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象或从现有对象中获取类型,然后调用类型的方法或访问其字段和属性。反射通常具有以下用途。
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法来调用特定的构造函数。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
        System.Reflection.Emit命名空间的类提供了一种特殊形式的反射,可以在运行时构造类型。
        反射也可用于创建称为类型浏览器的应用程序,使用户能够选择类型,然后查看有关选定类型的信息。
        此外,Jscript等语言编译器使用反射来构造符号表。System.Runtime.Serialization命名空间中的类使用反射来访问数据并确定要永久保存的字段,System.Runtime.Remoting命名空间中的类通过序列化来间接地使用反射。

1.2 反射技术示例
        下面是反射技术的示例,我们可以在程序去得时动态实例化对象,获得对象的属性,并调用对象的方法。
1Namespace ReflectionExample
2{
3 class Class1
4 {
5      [STAThread]
6      static void Main (string [ ] args)
7      {
8          System.Console.WriteLine(“列出程序集中的所有类型”);
9          Assembly a = Assembly.LoadFrom (“ReflectionExample.exe”);
10          Type[ ] mytypes = a.GetTypes( );
11
12          Foreach (Type t in mytypes)
13          {
14              System.Console.WriteLine ( t.Name );
15          }
16          System.Console.ReadLine ( );
17      System.Console.WriteLine (“列出HellWord中的所有方法” );
18      Type ht = typeof(HelloWorld);
19      MethodInfo[] mif = ht.GetMethods();
20      foreach(MethodInfo mf in mif)
21      {
22          System.Console.WriteLine(mf.Name);
23      }
24      System.Console.ReadLine();
25      System.Console.WriteLine("实例化HelloWorld,并调用SayHello方法");
26      Object obj = Activator.CreateInstance(ht);
27      string[] s = {"zhenlei"};
28      Object bojName = Activator.CreateInstance(ht,s);
29      BindingFlags flags = (BindingFlags.NonPublic|BindingFlags.Public|BindingFlags.Static|BindingFlags.Instance|BindingFlags.DeclaredOnly);
30      MethodInfo msayhello = ht.GetMethod("SayHello");
31      msayhello.Invoke(obj,null);
32      msayhello.Invoke(objName,null);
33      System.Console.ReadLine();
34    }
35    }
36}
1using System;
2namespace ReflectionExample
3{
4    public class HelloWorld
5    {
6        string myName = null;
7        public HelloWorld(string name)
8        {
9            myName = name;
10        }
11        public HelloWorld() : this(null)
12        {}
13        public string Name
14        {
15            get
16            {
17                return myName;
18            }
19        }
20        public void SayHello()
21        {
22            if(myName == null)
23            {
24                System.Console.WriteLine("Hello World");
25            }
26            else
27            {
28                System.Console.WriteLine("Hello," + myName);
29            }
30        }
31    }
32}
33
1.3 在设计模式实现中使用反射技术
        采用反射技术可以简化工厂的实现。
(1)工厂方法:通过反射可以将需要实现的子类名称传递给工厂方法,这样无须在子类中实现类的实例化。
(2)抽象工厂:使用反射可以减少抽象工厂的子类。
        采用反射技术可以简化工厂代码的复杂程度,在.NET项目中,采用反射技术的工厂已经基本代替了工厂方法。
        采用反射技术可以极大地简化对象的生成,对以下设计模式的实现也有很大影响。
(1)命令模式:可以采用命令的类型名称作为参数直接获得命令的实例,并且可以动态执行命令。
(2)享元模式:采用反射技术实例化享元可以简化享元工厂。

2 委托技术与设计模式
        委托技术是.NET引入的一种重要技术,使用委托可以实现对象行为的动态绑定,从而提高设计的灵活性。

2.1 .NET中的委托技术
        .NET运行库支持称为“委托”的引用类型,其作用类似于C++中的函数指针。与函数指针不同,委托实例独立于其封装方法的类,主要是那些方法与委托类型兼容。另外,函数指针只能引用静态函数,而委托可以引用静态和实例方法。委托主要用于.NET Framework中的事件处理程序和回调函数。
        所有委托都从System.Delegate继承而来并且有一个调用列表,这是在调用委托时所执行方法的一个链接列表。产生的委托可以用匹配的签名引用任何方法,没有为具有返回类型并在调用列表中包含多个方法的委托定义返回值。
        可以使用的委托Cimbine及Remove方法在其调用列表中添加和移除方法。若要调用委托,可使用Invoke方法,或者使用BeginInvoke和EndInvoke方法异步调用委托。委托类的实现由运行库提供,而不由用户代码提供。
        委托适用于那种在某些语言中需要用函数指针来解决的情况,但是与函数指针不同,它是面向对象和类型安全的。
        委托声明定义一个类,它是从System.Delegate类派生的类。委托实例封装了一个调用列表,其中列出了一个或多个方法,每个方法称为一个可调用实体。对于实例方法,可调用实体由一个实例和该实例的方法组成;对于静态方法,可调用实体仅由一个方法组成。如果用一组合适的参数来调用一个委托实例,则该委托实例所封装的每个可调用实体都会被调用,并且使用上述同一组参数。
        委托实例的一个有用的属性是它既不知道,也不关心其封装方法所属类的详细信息,对它来说最重要的是这些方法与该委托的类型兼容。即只要方法的返回类型和参数表是相同的,则方法与委托类型兼容,方法的名称不一定要与委托类相同。
定义和使用委托分为声明、实例化和调用3个步骤。委托用委托声明语法声明,如:
    delegate void myDelegate( );
声明一个名为myDelegate的委托,它不带参数并且不返回任何结果,如:
class Test
{
       static void F( )
      {
              System.Console.WriteLine (“Test.F”);
      }
       static void Main ( )
      {
            myeDelegate d = new myDelegate (F);
            d ( );
      }
}
创建一个myDelegate实例,然后立即调用它。这样做并没有太大的意义,因为直接调用方法会更简单。当涉及其匿名特性时,委托才能真正显示出其效果,如:
    void MultiCall (myDelegate d, int count ) {
      for (int I = 0; I < count; I++) {
        d( );
      }
    }
显示一个重复调用 myDelegate的MultiCall 方法,这个方法不知道,也不必知道myDelegate的目标方法的类型、该方法具有的可访问性或者是否为静态。对它来说最重要的是目标方法与myDelegate兼容。

2.2示例
        下面的例子说明了委托的实现,代码如下:
1using System;
2namespace DelegateExample
3{
4    public class TemplateMethod
5    {
6        public delegate float Comp(float a,float b);
7        public Comp myComp;
8        public TemplateMethod()
9        {}
10        public float DoComp(float[] f)
11        {
12            float nf = float.NaN;
13            foreach(float df in f)
14            {
15                if(float.IsNaN(nf))
16                    nf = df;
17                else
18                    nf = myComp(nf,df);
19            }
20            return nf;
21        }
22
23    }
24}
2.3 委托技术与GOF设计模式中委托的关系
        需要指出的是,.NET中的委托技术与GOF在《设计模式》中所提列的委托的意图一致,但在实现方法上有相当大的区别。.NET中的委托更进一步地降低了对象间的耦合性,将静态的组合关系变为运行时的动态组合关系。
        GOF在《设计模式》中定义的委托是:“委托是一种组合方法,它使组合具有与继承同样的复用能力。在委托方式下,有两个对象参与处理一个请求,接受请求的对象将操作委托给它的代理者(delegate),它类似于子类将请求交给它的父类处理。使用继承时,被继承的操作总能引用接受请求的对象。在C++中通过this成员变量,在Smalltalk中则通过self。委托方式为了得到同样的效果,接受请求的对象将自身传给被委托者(代理人),使被委托的操作可以引用接受请求的对象。”
        如果采用.NET的委托技术,上述结构可以更加灵活。Window不引用Rectangle即可实现Area的计算,为此首先声明一个计算面积的委托定义,示例代码如下:
    public delegate float Darea();
然而在Window类中声明与这个代理一致的接口:
    class Window
    {
        public Darea Area;
    }
这里不需要引用Rectangle类,只是在执行时动态绑定即可:
Rectangle rc = new Rectangle();
Window w = new Window();
w.Area = new Darea(rc.Area);
        这样当调用w的Area时,实际调用的是Reactangel的Area方法。从实现意图上看,.NET的委托更好地实现了GOF所阐述的意图,结构上也更为灵活。但这两种委托解决的不是一个层面的问题,GOF的委托强调的是一种策略,而.NET和委托技术则是具体实现。

2.4 委托技术与设计模式实现
        采用委托技术可以进一步实现用组合代替继承的思路,很多采用继承实现的关系可以采用委托实现。采用委托可以简化下列设计模式的使用。
(1)模板方法:这种方法采用继承实现具体方法,采用委托可以动态实现方法的组合。
(2)观察者:可以使用事件委托实现观察者与主题之间的通信。
(3)中介者:使用委托可以去除工件与中介者之间的耦合关系。

转载于:https://www.cnblogs.com/sainaxingxing/archive/2008/08/22/1274392.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/411631.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python之yield的一些应用

生成器 yield是用于生成器。生成器通俗的认为&#xff0c;在一个函数中&#xff0c;使用了yield来代替return的位置的函数&#xff0c;就是生成器。它不同于函数的使用方法是&#xff1a;函数使用return来进行返回值&#xff0c;每调用一次&#xff0c;返回一个新加工好的数据返…

本题要求实现一个用选择法对整数数组进行简单排序的函数。_通俗易懂讲 Python 算法:快速排序...

原文&#xff1a;https://stackabuse.com/quicksort-in-python/作者&#xff1a;Marcus Sanatan译者&#xff1a;老齐欢迎在 bilibili 搜索 freeCodeCamp 官方账号或者直接访问 https://space.bilibili.com/335505768 观看我们的技术视频介绍快速排序是一种流行的排序算法&…

[jQuery]JQuery一个对象可以同时绑定多个事件,这是如何实现的?

JQuery一个对象可以同时绑定多个事件&#xff0c;这是如何实现的&#xff1f; ①$(document).ready(function() {$("button").bind({click: function() {$("p").slideToggle()},mouseover: function() {$("body").css("background-color&q…

张娟娟(为奥运冠军名字作诗)

张娟娟&#xff08;为奥运冠军名字作诗&#xff09;——代腾飞 2008年8月18日 于成都张弓搭箭射靶心娟娟俊美胜古今娟弓即破他人梦百步穿杨改乾坤 转载于:https://www.cnblogs.com/daitengfei/archive/2008/08/25/1276023.html

IO_ADDRESS()的实现【转】

上面我们说了如何去在系统中自己实现一个设置系统寄存器的一个方法&#xff0c;上面归根到底要进行物理地址到虚拟地址的映射 现在我们就说说IO_ADDRESS()的实现 #define __REG32ALI&#xff08;addr) (*((volatile unsigned long *)((addr) - ALI_REGS_PHYS_BASE ALI_REGS_V…

vscode标记_高效扩展工具让 VS Code 如虎添翼

Codelf 变量命名神器Star&#xff1a;10688https://github.com/unbug/codelf新建项目&#xff0c;变量&#xff0c;类&#xff0c;方法&#xff0c;接口都需要命名&#xff0c;一个好的命名可以一眼看出这个地方的功能&#xff0c;CodeIf 一键起名不再难&#xff0c;输入关键词…

[html] 如何实现标题栏闪烁、滚动的效果

[html] 如何实现标题栏闪烁、滚动的效果 定时器背景设置个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

各种数据库连接字符串

1、ACCESS数据库连接set conn Server.CreateObject("ADODB.Connection")conn.Open("driver{Microsoft Access Driver (*.mdb)};dbq" &_Server.MapPath("person.mdb"))set rs conn.Execute( "SELECT * FROM grade" )For I 0 to …

linux服务器情况

查看Linux 进程命令 ps -aux 或者ps -ef linux 进程很多 如果需要查找某一个进程可以使用 管道和grep命令 Linux下常用命令 grep 匹配字符 ps 查询Linux进程 1.查看服务器CPU飙升卡爆&#xff0c;最后发现是服务器在跑挖矿程序&#xff0c;CPU使用率奇高。在此总结…

[html] 页面导入样式时,使用link和@import有什么区别?

[html] 页面导入样式时&#xff0c;使用link和import有什么区别&#xff1f; 区别&#xff1a; 1.link是HTML标签&#xff0c;import是css提供的。 2.link引入的样式页面加载时同时加载&#xff0c;import引入的样式需等页面加载完成后再加载。 3.link没有兼容性问题&#xff…

CSS 有关Position = absolute (绝对定位 是相对于谁而言)

css中有绝对定位法&#xff0c;以前一直搞不懂绝对定位是相对于谁而言的绝对定位。 现在搞清楚了&#xff0c;不是相对于父元素&#xff0c;也不是相对于BODY。 而是相对于所属元素树中&#xff0c;相邻最近的那个显示标识了position属性的元素。 比如 Code<div id"a&q…

[html] 简述超链接target属性的取值和作用

[html] 简述超链接target属性的取值和作用 _self: 在当前窗口打开页面 _blank: 在新窗口打开页面 _top: 在整个框架打开页面不是很理解个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣…

mysql gui vim_vim(一): 小技巧

1) 如何yank字符然后再查找 ( / Ctrl - R 0 ) The most recently yanked text will be stored in the 0 and registers (if no register was explicitly specified e.g. by xy ). Then you can paste the text of any that register in the last line (eith1) 如何yank字符然后…

服务端和客户端

1.一般来说&#xff0c;客户端就是我们使用的电脑&#xff08;包括我们使用的浏览器IE,Firefox&#xff09;&#xff1b;服务器端就是存放网页与数据库数据的服务器。 2.你是客户&#xff0c;因为你在访问&#xff0c;你访问的是服务端。去吃饭&#xff0c;你到饭店&#xff0c…

mysql 判断质数_java之判断输入的数是否为素数

import java.util.Scanner;public class TestIsSushu {public static void main(String[] args) {Scanner scan new Scanner(System.in);System.out.println("输入正整数&#xff1a;");int i scan.nextInt();if(i<0) {System.out.println("输入错误&#…

LeetCode Smallest Range

数据范围是3500,3500也就是说n的平方是可以接受的。这里告诉你就是有序的,也就是在提醒你可能会是一个类似于二分的算法,所以的话其实基于这两个认识的话我们就可以利用一个枚举叫二分的算法来解决这道题。怎么做呢&#xff1f;就首先的话我们要枚举一端,一端的话我们可以把所有…

Oracle创建用户、表空间、导入导出、...命令

//创建临时表空间create temporary tablespace test_temp tempfile E:\oracle\product\10.2.0\oradata\testserver\test_temp01.dbf size 32m autoextend on next 32m maxsize 2048mextent management local;//创建数据表空间create tablespace test_dataloggingdatafile E:\or…

[html] 简述下html5的离线储存原理,同时说明如何使用?

[html] 简述下html5的离线储存原理&#xff0c;同时说明如何使用&#xff1f; 原理&#xff1a;HTML5的离线存储是基于一个新建的.appcache文件的缓存机制(不是存储技术)&#xff0c;通过这个文件上的解析清单离线存储资源&#xff0c;这些资源就会像cookie一样被存储了下来。…

DCX读书报告Bring structure to the web有感

DCX今天做的学术报告直接采用MSRA荣研究员的“Bring Structure to the web”的PPT&#xff0c;读的效果很不错&#xff0c;看样子是下功夫了&#xff0c;他理解了80%以上 当然学术报告与读书报告&#xff1a; 1、从形式上而言&#xff0c;都应该采用中文&#xff0c;源图须重画…

Web前端3.0时代,“程序猿”如何“渡劫升仙”

Web前端入行门槛低&#xff0c;很多人在成为前端工程师后很容易进入工作的舒适区&#xff0c;认为该熟悉的业务已熟悉了&#xff0c;然后就是重复用轮子&#xff0c;这样很容易让自己的成长处于原地打转以及低水平重复的状态。 想要不被行业抛弃&#xff0c;就要努力提升自己。…