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