扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
反射(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)工厂方法:通过反射可以将需要实现的子类名称传递给工厂方法,这样无须在子类中实现类的实例化。
(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 DelegateExample3{4 public class TemplateMethod5 {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 else18 nf = myComp(nf,df);19 }20 return nf;21 }2223 }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)中介者:使用委托可以去除工件与中介者之间的耦合关系。
婵犵數濮烽弫鍛婃叏閻戝鈧倹绂掔€n亞鍔﹀銈嗗坊閸嬫捇鏌涢悢閿嬪仴闁糕斁鍋撳銈嗗坊閸嬫挾绱撳鍜冭含妤犵偛鍟灒閻犲洩灏欑粣鐐烘⒑瑜版帒浜伴柛鎾寸洴閹儳煤椤忓應鎷洪梻鍌氱墛閸楁洟宕奸妷銉ф煣濠电姴锕ょ€氼參宕h箛鏃傜瘈濠电姴鍊绘晶娑㈡煕鐎c劌濡介柕鍥у瀵粙濡歌閳ь剚甯¢弻鐔兼寠婢跺﹥娈婚梺鍝勭灱閸犳牠骞冨⿰鍫濈厸闁稿本绋撹ぐ瀣煟鎼淬値娼愭繛鍙壝悾婵堢矙鐠恒劍娈鹃梺鍓插亝濞叉牠鎮″☉銏$厱閻忕偛澧介惌瀣箾閸喐鍊愭慨濠勭帛閹峰懐绮电€n亝鐣伴梻浣规偠閸斿宕¢崘鑼殾闁靛繈鍊曢崘鈧銈嗗姂閸庡崬鐨梻鍌欑劍鐎笛呯矙閹寸姭鍋撳鐓庡籍鐎规洑鍗冲畷鍗炍熼梹鎰泿闂備線娼ч悧鍡涘箠鎼淬垺鍙忔い鎺嗗亾闁宠鍨块崺銉╁幢濡炲墽鍑规繝鐢靛О閸ㄦ椽鏁嬮柧鑽ゅ仦娣囧﹪濡堕崨顔兼闂佺ǹ顑呴崐鍦崲濞戙垹骞㈡俊顖濐嚙绾板秹鏌f惔銏e妞わ妇鏁诲璇差吋閸偅顎囬梻浣告啞閹搁箖宕版惔顭戞晪闁挎繂顦介弫鍡椼€掑顒婂姛闁活厽顨嗙换娑㈠箻閺夋垹鍔伴梺绋款儐閹瑰洭寮婚敐鍛婵炲棙鍔曠壕鎶芥⒑閸濆嫭婀扮紒瀣灴閸╃偤骞嬮敃鈧婵囥亜閺囩偞鍣洪柍璇诧功缁辨捇宕掑▎鎴濆濡炪們鍔岄幊姗€骞嗗畝鍕<闁绘劙娼х粊锕傛煙閸忚偐鏆橀柛鏂跨焸閹偤宕归鐘辩盎闂佸湱鍎ら崹鐢割敂閳哄懏鍊垫慨姗嗗墻濡插綊鏌曢崶褍顏€殿喕绮欐俊姝岊槼闁革絻鍎崇槐鎾存媴缁涘娈┑鈽嗗亝缁诲牆顕f繝姘亜缁炬媽椴搁弲锝夋偡濠婂啰效闁诡喗锕㈤幊鐘活敆閸屾粣绱查梺鍝勵槸閻楀嫰宕濇惔锝囦笉闁绘劗鍎ら悡娑㈡倶閻愯泛袚闁哥姵锕㈤弻鈩冩媴閻熸澘顫掗悗瑙勬礈閸犳牠銆佸鈧幃鈺呮惞椤愩倝鎷婚梻鍌氬€峰ù鍥х暦閸偅鍙忛柟鎯板Г閳锋梻鈧箍鍎遍ˇ顖炲垂閸岀偞鐓㈡俊顖滃皑缁辨岸鏌ㄥ┑鍡╂Ц缂佲偓鐎n偁浜滈柡宥冨妿閳藉绻涢崼鐔虹煉婵﹨娅e☉鐢稿川椤斾勘鈧劕顪冮妶搴′簼婵炶尙鍠栧畷娲焵椤掍降浜滈柟鍝勬娴滈箖姊洪幐搴㈢┛濠碘€虫搐鍗遍柟鐗堟緲缁秹鏌涢锝囩畼妞ゆ挻妞藉铏圭磼濡搫顫岄悗娈垮櫘閸撴瑨鐏冮梺鍛婁緱閸犳岸宕㈤幖浣光拺闁告挻褰冩禍浠嬫煕鐎n亜顏柟顔斤耿閺佸啴宕掑☉姘箞闂佽鍑界紞鍡涘磻閸℃ɑ娅犳い鎺戝€荤壕濂告煕鐏炲墽鈽夌紒妞﹀洦鐓欓柣鐔告緲椤忣參鏌熼悡搴㈣础闁瑰弶鎸冲畷鐔兼濞戞瑦鐝¢梻鍌氬€搁崐椋庣矆娓氣偓楠炴牠顢曢妶鍌氫壕婵ê宕崢瀵糕偓瑙勬礀缂嶅﹪寮婚崱妤婂悑闁告侗鍨界槐閬嶆煟鎼达紕鐣柛搴ㄤ憾钘濆ù鍏兼綑绾捐法鈧箍鍎遍ˇ浼存偂閺囥垺鐓涢柛銉e劚婵$厧顭胯閸ㄤ即婀侀梺缁樓圭粔顕€顢旈崼鐔虹暢闂傚倷鐒︾€笛呮崲閸屾娑樜旈崨顓犲幒闂佸搫娲㈤崹娲偂閸愵亝鍠愭繝濠傜墕缁€鍫熸叏濡寧纭鹃柦鍐枛閺屾洘绻涜鐎氱兘宕戦妸鈺傗拺缂備焦锚婵洦銇勯弴銊ュ籍闁糕斂鍨藉鎾閳ユ枼鍋撻悽鍛婄叆婵犻潧妫楅埀顒傛嚀閳诲秹宕堕妸锝勭盎闂婎偄娲︾粙鎰板箟妤e啯鐓涢悘鐐靛亾缁€瀣偓瑙勬礋娴滃爼銆佸鈧幃銏$附婢跺澶�
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者