詳解LINQ to Reflection反射機(jī)制
引言
我們平時(shí)開發(fā)中不可避免,或者說(shuō),經(jīng)常性的使用反射。但是卻沒有一個(gè)合適的類庫(kù)幫助我們更好的利用反射。從早期的FastInvoker,到老趙的 fastreflectionlib ,無(wú)一不是在強(qiáng)調(diào)Fast。這是因?yàn)榉瓷涞男阅軗p耗比較厲害,所以大家都集中精力解決性能的問(wèn)題,但是在易用性方面卻鮮有改進(jìn)。今天我為大家?guī)?lái)一個(gè)即兼顧性能又具有良好的使用體驗(yàn)的反射類庫(kù).
.Metadata()
此類庫(kù)以LINQ TO Object為基礎(chǔ),可以通過(guò)調(diào)用.Metadata()方法獲取對(duì)應(yīng)Type的完整Metadata信息。此信息會(huì)被進(jìn)行緩存,并且使用fastreflectionlib的核心Lambda代碼,利用DynamicMethod代替直接的反射執(zhí)行。
- public static Metadata Metadata(this object instance)
- {
- return MetadataCache.Create(instance);
- }
先定義一個(gè)MockObject
- class MockAttribute : Attribute
- {
- public MockAttribute(string name) {
- this.Name = name;
- }
- public string Name
- { get;set;
- } }
- class MockObject
- {
- public string Country = "China";
- [Mock("this is the name")]
- public string Name
- { get;set; }
- public string Blog
- { get;set;
- }
- [Mock("this is the location")]
- public string Location
- { get;set; }
- public string SayHello(string name) {
- return "Hi," + name;
- } } }
1.如何獲取一個(gè)屬性,并進(jìn)行取值、賦值?
- using Sparrow.Reflection;
- [TestMethod]
- public void set_property_value()
- {
- var obj = new MockObject { Name = "dayi", Blog = "http://walkingboy.cnblogs.com", Location = "XiaMen" };
- var property = obj.Metadata().Properties.Where(i => i.Name == "Location").FirstOrDefault();
- var changedLocation = "Xiamen,China";
- //get value
- //var value = property.GetValue(obj);
- property.SetValue(obj, changedLocation);
- Assert.AreEqual(changedLocation, obj.Location);
- }
2.如果獲取一個(gè)字段的值?
- using Sparrow.Reflection;
- [TestMethod]
- public void get_field_value()
- {
- var obj = new MockObject();
- var field = obj.Metadata().Fields.Where(i => i.Name == "Country").FirstOrDefault();
- Assert.AreEqual("China", field.GetValue(obj));
- }
3.如何獲取一個(gè)自定義CustomAttribute?
- using Sparrow.Reflection;
- [TestMethod]
- public void get_custom_attribute_data() {
- var obj = new MockObject { Name = "dayi", Blog = "http://walkingboy.cnblogs.com", Location = "XiaMen" };
- var attribute = obj.Metadata().Properties
- .Where(i => i.Name == "Name")
- .SelectMany(i => i.Attributes)
- .Select(i=>i.Attribute)
- .OfType<MockAttribute>()
- .FirstOrDefault();
- Assert.AreEqual("this is the name", attribute.Name);
- }
4.如何調(diào)用一個(gè)指定名稱的Method?
- using Sparrow.Reflection;
- [TestMethod]
- public void invoke_method()
- {
- var obj = new MockObject();
- var method = obj.Metadata().Methods.Where(i => i.Name == "SayHello").FirstOrDefault();
- Assert.AreEqual("Hi,world",method.Invoke(obj,new []{"world"}));
- }.Proxy()
對(duì)于某些應(yīng)用場(chǎng)景來(lái)說(shuō),使用LINQ To Object去查詢并獲取單一的方法、屬性,字段,總覺得還是要寫非常多的代碼。要先.Metadata(), 接下來(lái).Where(), 雖然代碼很優(yōu)雅,但是還是有很多工作要做。所以這里也提供一個(gè)針對(duì)獲取單一方法、屬性、字段的替代寫法。
- public static Proxy Proxy(this object instance)
- {
- return new Proxy(instance);
- }
1.如何獲取一個(gè)屬性的值
- using Sparrow.Reflection;
- [TestMethod]
- public void get_value_via_property_proxy() {
- var obj = new MockObject { Name = "dayi", Blog = "http://walkingboy.cnblogs.com", Location = "Xiamen" };
- Assert.AreEqual(obj.Name, obj.Proxy().Properties["Name"]);
- }
2.如何設(shè)置一個(gè)屬性的值
- using Sparrow.Reflection;
- [TestMethod]
- public void set_value_via_property_proxy() {
- var obj = new MockObject
- { Name = "dayi", Blog = "http://walkingboy.cnblogs.com", Location = "Xiamen" };
- var changedLocation = "Xiamen,China";
- obj.Proxy().Properties["Location"] = changedLocation;
- Assert.AreEqual(changedLocation,obj.Location);
- }
3.如何獲取一個(gè)字段的值
- using Sparrow.Reflection;
- [TestMethod]
- public void get_value_via_field_proxy() {
- var obj = new MockObject
- { Name = "dayi", Blog = "http://walkingboy.cnblogs.com", Location = "Xiamen" };
- Assert.AreEqual(obj.Country, obj.Proxy().Fields["Country"]);
- }
4.如何調(diào)用一個(gè)方法
- using Sparrow.Reflection;
- [TestMethod]
- public void invoke_method_via_method_proxy() {
- var obj = new MockObject();
- Assert.AreEqual("Hi,world", obj.Proxy().Methods["SayHello"](new []{"world"}));
- }.Proxy() Vs Dynamic
我們知道在C# 4中引入了關(guān)鍵字Dynamic,使得 Duck Typing (DynamicDuck: Duck Typing in a Dynamic World)
成為一種可能。 查看如下代碼
- public void Run(dynamic obj)
- { Console.WriteLine(obj.Name);
- }
這個(gè)代碼并沒有指定參數(shù)obj的類型,obj的類型是由運(yùn)行時(shí)候傳入的真實(shí)值決定,只要該類型包含一個(gè)Name的屬性就可以了。
但是僅僅支持Duck Typing就夠了嘛? 似乎不夠動(dòng)態(tài)哦。這邊的.Name 是在編譯時(shí)(或者說(shuō)編碼時(shí))就確定,但是往往我們的使用場(chǎng)景中,連這個(gè)也都是動(dòng)態(tài),比如是接受自Form,或者來(lái)自配置信息,這個(gè)時(shí)候dynamic就無(wú)能為力了。
反過(guò)來(lái)看看使用.Proxy()的情況
- public void Run(object obj,string propertyName) {
- Console.WriteLine(obj.Proxy().Properties[propertyName])
- }
原文標(biāo)題:LINQ TO Reflection
鏈接:http://www.cnblogs.com/walkingboy/archive/2010/08/11/linq-to-reflection.html
【編輯推薦】