Reflection(反射)是深刻学习.Net必须掌握的技能之一。最初学Reflection的时候,的确是被惊住了,原来还能够这样。只要给你一个Assembly, 你就能获取到其中全部的类型,根据类型,你可以建立和操做对象的属性和方法,甚至是私有的。可是,每次使用Reflection,看着那些丑陋难懂的代码,都让人不敢直视。下面就介绍一些在特定场景下能够替换Reflection的方法。html
咱们首先建立一个Person类,这个类很是简单,一个Name的public属性,一个_age的私有变量。完整代码以下:git
public class Person { private readonly int _age; public Person(int age) { _age = age; } public string Name { get; set; } public bool GuessAge(int age) { return _age == age; } }
接下来,看看常规的使用reflection获取一个person对象公开属性,私有变量同时调用对象的方法:github
var type = p.GetType(); var property = type.GetProperty("Name");//根据名称获取类型属性 Console.WriteLine(property.GetValue(p).ToString());//获取对象的属性值 var field = type.GetField("_age", BindingFlags.NonPublic | BindingFlags.Instance);//获取私有变量_age, 后面的BindingFlags很是重要,不然默认是不可以取到private的东西 Console.WriteLine(field.GetValue(p)); var guessResult = type.InvokeMember("GuessAge", BindingFlags.InvokeMethod, null, p, new object[] { 20 });//调用对象的方法 Console.WriteLine(guessResult);
来看看输出结果:ide
什么是PrivateObject, PrivateObject是微软在单元测试中引入的,本意是方便咱们写单元测试的时候,对于私有变量,方法,可以很是简单方便的调用。可是这也不妨碍咱们在开发代码中使用。使用PrivateObject只须要引用Microft.VisualStudio.QualityTools.UnitTestFramework单元测试
接下来看看,如何使用PrivateObject来实现:学习
var privateObject = new PrivateObject(p); Console.WriteLine(privateObject.GetProperty("Name")); Console.WriteLine(privateObject.GetField("_age")); Console.WriteLine(privateObject.Invoke("GuessAge", new object[] { 20 }));
上面的代码和使用Reflection的效果彻底同样。是否是以为整个世界都清净许多。在代码的可读性上面,比Reflection好很多。测试
使用动态类型,能够很是简单方便的访问对象的属性的方法,好比上面的代码,若是我用dynamic实现:ui
dynamic person = p; Console.WriteLine(person.Name); //Console.WriteLine(person._age); Console.WriteLine(person.GuessAge(20));
使用dynamic的前提是,你在写代码的时候,就须要知道该对象的确切的属性名字和方法名,不能做为参数传递。而上面的Refelction和PrivateObject是能够的。
使用dynamic还有一个缺点,就是没法访问到对象的私有成员。这也是注释掉_age输出的缘由。spa
真实的使用场景是,能够在不须要定义接口的状况下,实现通用的代码。好比Person有个Start属性, Car也有个Start属性,有个功能是须要为由Start的东西,显示的时候,都要带个星星的图标,这个时候,使用dynamic,就可以写出同时支持Person和Car的方法。翻译
使用dynamic不能访问私有成员的问题,在Exposed里获得彻底解决,从名字(翻译成暴露)也能看出来,它就是干这个的。
var exposedObj = Exposed.From(p); Console.WriteLine(exposedObj.Name); Console.WriteLine(exposedObj._age); Console.WriteLine(exposedObj.GuessAge(20));
Exposed是第三方开源的,项目地址是https://github.com/Cognifide/ExposedObject,也能够在nuget中下载到。
看到上面的“废话”,动态语言的爱好者只会冷笑一下,丑陋的静态编译语言,这些东西在动态语言里面,“这都不是事”。好吧,我认可,可是看完了Clay,也许能改变你的见解。
dynamic New = new ClayFactory(); var person = New.Person().Name("Louis")._age(30); person.GuessAge = new Func<int, bool>(x => x == person._age); Console.WriteLine(person.Name); Console.WriteLine(person._age); Console.WriteLine(person.GuessAge()(20));
跟多的了解Clay,能够看这篇http://www.cnblogs.com/JustRun1983/p/3529157.html