详解LINQ to Reflection反射机制

开发 后端
本文将讨论的是LINQ的反射机制。需要解决的是反射性能损耗问题,其次就是易用性方面的改进,希望对大家有所帮助。

引言

我们平时开发中不可避免,或者说,经常性的使用反射。但是却没有一个合适的类库帮助我们更好的利用反射。从早期的FastInvoker,到老赵的 fastreflectionlib ,无一不是在强调Fast。这是因为反射的性能损耗比较厉害,所以大家都集中精力解决性能的问题,但是在易用性方面却鲜有改进。今天我为大家带来一个即兼顾性能又具有良好的使用体验的反射类库.

.Metadata()

此类库以LINQ TO Object为基础,可以通过调用.Metadata()方法获取对应Type的完整Metadata信息。此信息会被进行缓存,并且使用fastreflectionlib的核心Lambda代码,利用DynamicMethod代替直接的反射执行。

  1. public static Metadata Metadata(this object instance)         
  2.  {             
  3.  return MetadataCache.Create(instance);      
  4.     }      

先定义一个MockObject

  1. class MockAttribute : Attribute        
  2.   {              
  3. public MockAttribute(string name)            {                 
  4.  this.Name = name;         
  5.      }          
  6.     public string Name        
  7.       {                get;set;          
  8.     }        }       
  9.    class MockObject       
  10.    {          
  11.     public string Country = "China";                   
  12.        [Mock("this is the name")]      
  13.         public string Name      
  14.         {                get;set;            }         
  15.      public string Blog        
  16.       {                get;set;     
  17.          }            
  18.   [Mock("this is the location")]        
  19.       public string Location     
  20.          {                get;set;            }            
  21.   public string SayHello(string name)            {              
  22.     return "Hi," + name;        
  23.       }        }    } 

1.如何获取一个属性,并进行取值、赋值?

  1. using Sparrow.Reflection;          
  2. [TestMethod]          
  3. public void set_property_value()         
  4.  {              
  5. var obj = new MockObject { Name = "dayi", Blog = "http://walkingboy.cnblogs.com", Location = "XiaMen" };              
  6. var property = obj.Metadata().Properties.Where(i => i.Name == "Location").FirstOrDefault();             
  7.  var changedLocation = "Xiamen,China";             
  8.  //get value  
  9.  //var value = property.GetValue(obj);  
  10. property.SetValue(obj, changedLocation);  
  11. Assert.AreEqual(changedLocation, obj.Location);  
  12.         }    

2.如果获取一个字段的值?

  1. using Sparrow.Reflection;          
  2. [TestMethod]          
  3. public void get_field_value()         
  4.  {              
  5. var obj = new MockObject();              
  6. var field = obj.Metadata().Fields.Where(i => i.Name == "Country").FirstOrDefault();  
  7. Assert.AreEqual("China", field.GetValue(obj));         
  8.  }    

3.如何获取一个自定义CustomAttribute?

  1. using Sparrow.Reflection;          
  2. [TestMethod]          
  3. public void get_custom_attribute_data()        {              
  4. var obj = new MockObject { Name = "dayi", Blog = "http://walkingboy.cnblogs.com", Location = "XiaMen" };             
  5.  var attribute = obj.Metadata().Properties                 
  6.  .Where(i => i.Name == "Name")                 
  7.  .SelectMany(i => i.Attributes)                 
  8.  .Select(i=>i.Attribute)                  
  9. .OfType<MockAttribute>()                  
  10. .FirstOrDefault();              
  11. Assert.AreEqual("this is the name", attribute.Name);        
  12.   }   

4.如何调用一个指定名称的Method?

  1. using Sparrow.Reflection;          
  2. [TestMethod]          
  3. public void invoke_method()       
  4.    {              
  5. var obj = new MockObject();              
  6. var method = obj.Metadata().Methods.Where(i => i.Name == "SayHello").FirstOrDefault();  
  7. Assert.AreEqual("Hi,world",method.Invoke(obj,new []{"world"}));       
  8.    }.Proxy() 

对于某些应用场景来说,使用LINQ To Object去查询并获取单一的方法、属性,字段,总觉得还是要写非常多的代码。要先.Metadata(), 接下来.Where(), 虽然代码很优雅,但是还是有很多工作要做。所以这里也提供一个针对获取单一方法、属性、字段的替代写法。

  1. public static Proxy Proxy(this object instance)  
  2.         {  
  3.             return new Proxy(instance);  
  4.         } 

1.如何获取一个属性的值

  1. using Sparrow.Reflection;          
  2. [TestMethod]          
  3. public void get_value_via_property_proxy()        {             
  4.  var obj = new MockObject { Name = "dayi", Blog = "http://walkingboy.cnblogs.com", Location = "Xiamen" };             
  5.  Assert.AreEqual(obj.Name, obj.Proxy().Properties["Name"]);   
  6.        } 

2.如何设置一个属性的值

  1. using Sparrow.Reflection;     
  2.      [TestMethod]       
  3.    public void set_value_via_property_proxy()        {            
  4.   var obj = new MockObject 
  5. { Name = "dayi", Blog = "http://walkingboy.cnblogs.com", Location = "Xiamen" };           
  6.    var changedLocation = "Xiamen,China";      
  7.       obj.Proxy().Properties["Location"] = changedLocation;       
  8.        Assert.AreEqual(changedLocation,obj.Location);      
  9.     }  

3.如何获取一个字段的值

  1. using Sparrow.Reflection;          
  2. [TestMethod]          
  3. public void get_value_via_field_proxy()        {             
  4.  var obj = new MockObject 
  5. { Name = "dayi", Blog = "http://walkingboy.cnblogs.com", Location = "Xiamen" };              
  6. Assert.AreEqual(obj.Country, obj.Proxy().Fields["Country"]);      
  7.     } 

4.如何调用一个方法

  1. using Sparrow.Reflection;          
  2. [TestMethod]          
  3. public void invoke_method_via_method_proxy()        {              
  4. var obj = new MockObject();            
  5. Assert.AreEqual("Hi,world", obj.Proxy().Methods["SayHello"](new []{"world"}));       
  6.    }.Proxy() Vs Dynamic 

我们知道在C# 4中引入了关键字Dynamic,使得 Duck Typing (DynamicDuck: Duck Typing in a Dynamic World)

成为一种可能。 查看如下代码

  1. public void Run(dynamic obj)       
  2.    {              Console.WriteLine(obj.Name);  
  3.         }  

这个代码并没有指定参数obj的类型,obj的类型是由运行时候传入的真实值决定,只要该类型包含一个Name的属性就可以了。

但是仅仅支持Duck Typing就够了嘛? 似乎不够动态哦。这边的.Name 是在编译时(或者说编码时)就确定,但是往往我们的使用场景中,连这个也都是动态,比如是接受自Form,或者来自配置信息,这个时候dynamic就无能为力了。

反过来看看使用.Proxy()的情况

  1. public void Run(object obj,string propertyName)       {           
  2.    Console.WriteLine(obj.Proxy().Properties[propertyName])     
  3.     } 

原文标题:LINQ TO Reflection

链接:http://www.cnblogs.com/walkingboy/archive/2010/08/11/linq-to-reflection.html

【编辑推荐】

  1. Linq匿名类型简单概述
  2. Linq随机读取数据浅析
  3. Linq Lambda表达式全面分析
  4. Linq扩展方法简单分析
  5. 初探Linq局部变量类型
责任编辑:彭凡 来源: 博客园
相关推荐

2009-06-17 13:57:54

java实例Reflection

2011-05-26 15:23:34

JavaReflection

2011-03-09 09:11:52

java反射机制

2011-09-27 10:23:24

Java反射机制

2011-04-01 14:50:56

Java的反射机制

2010-02-04 11:23:25

C++反射机制

2009-09-16 09:47:15

Linq Tracki

2009-04-10 09:55:44

C#反射.NET

2012-04-05 13:50:38

Java

2009-09-08 17:27:18

LINQ to Dat

2009-09-18 14:51:19

LINQ TO SQL

2009-09-09 10:54:52

Linq存储过程返回

2017-05-17 15:28:15

Java反射机制

2017-03-24 09:44:33

Java反射机制

2009-09-14 16:17:03

什么是LINQ To

2009-09-14 14:49:12

LINQ查询基础知识

2009-09-14 13:17:51

LINQ to SQLLINQ to SQL

2009-09-03 11:00:29

C#反射机制

2010-06-03 08:55:43

LINQ

2009-11-27 09:41:56

LINQ
点赞
收藏

51CTO技术栈公众号