代替Reflection(反射)的一些方法


Reflection(反射)是深入學習.Net必須掌握的技能之一。最初學Reflection的時候,的確是被驚住了,原來還可以這樣。只要給你一個Assembly, 你就能獲取到其中所有的類型,根據類型,你能夠創建和操作對象的屬性和方法,甚至是私有的。但是,每次使用Reflection,看着那些丑陋難懂的代碼,都讓人不敢直視。下面就介紹一些在特定場景下可以替換Reflection的方法。

1. 使用Reflection完成的簡單Demo

我們首先創建一個Person類,這個類非常簡單,一個Name的public屬性,一個_age的私有變量。完整代碼如下:

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對象公開屬性,私有變量同時調用對象的方法:

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);

來看看輸出結果:

image

2. 使用PrivateObject

什么是PrivateObject, PrivateObject是微軟在單元測試中引入的,本意是方便我們寫單元測試的時候,對於私有變量,方法,能夠非常簡單方便的調用。但是這也不妨礙我們在開發代碼中使用。使用PrivateObject只需要引用Microft.VisualStudio.QualityTools.UnitTestFramework

image

接下來看看,如何使用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好不少。

3. 使用dynamic

使用動態類型,可以非常簡單方便的訪問對象的屬性的方法,比如上面的代碼,如果我用dynamic實現:

dynamic person = p;
Console.WriteLine(person.Name);
//Console.WriteLine(person._age);
Console.WriteLine(person.GuessAge(20));

使用dynamic的前提是,你在寫代碼的時候,就需要知道該對象的確切的屬性名字和方法名,不能作為參數傳遞。而上面的Refelction和PrivateObject是可以的。
使用dynamic還有一個缺點,就是無法訪問到對象的私有成員。這也是注釋掉_age輸出的原因。

真實的使用場景是,可以在不需要定義接口的情況下,實現通用的代碼。比如Person有個Start屬性, Car也有個Start屬性,有個功能是需要為由Start的東西,顯示的時候,都要帶個星星的圖標,這個時候,使用dynamic,就能夠寫出同時支持Person和Car的方法。

4. 使用Exposed

使用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中下載到。

5. 大殺器Clay

看到上面的“廢話”,動態語言的愛好者只會冷笑一下,丑陋的靜態編譯語言,這些東西在動態語言里面,“這都不是事”。好吧,我承認,但是看完了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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM