今天看《Linq in Action》时突然萌生了一个想法使用Expression和Linq来快速访问对象的属性。如果我们把一个对象放到数组中对其进行查询,然后使用select将需要的属性投影出来就可以达到快速访问的目的。虽然比直接访问要慢很多,但是比反射方式快1个数量级还是非常不错的。
假设有实体类定义如下:
public
class
User
...
{ public string Name ... { get ; set ; } public int Age ... { get ; set ; } }
如果我们想访问Name字段的值需要这样做
var books
=
new
User[]
...
{ new User ... {Name = " Lucifer " , Age = 26 } }
; var val
=
books.Select(book
=>
book.Name).First();
非常简单是吧,接下来只要把他用Expression翻译一下,并编成泛型的就可以了。代码如下:
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Linq.Expressions;
using
System.Diagnostics;
public
class
QuickAccess
<
T
>
...
{ static Dictionary < int , Delegate > __pMap = new Dictionary < int , Delegate > (); static T[] __lst = new T[] ... { default (T) } ; public static P Get_ProperyVal < P > (T obj, string pName) ... { var func = default (Func < T, P > ); __lst[ 0 ] = obj; try ... { func = (Func < T, P > )__pMap[pName.GetHashCode()]; } catch ... { /**/ /* * from param in __lst * select param.pName * */ var param = Expression.Parameter( typeof (T), " param " ); var body = Expression.Property(param, pName); var lambda = Expression.Lambda(body, param); __pMap.Add(pName.GetHashCode(), lambda.Compile()); func = (Func < T, P > )__pMap[pName.GetHashCode()]; } return Enumerable.Select(__lst, func).First(); } }
//
调用代码
int
val
=
0
; var user
=
new
User
...
{ Name = " Lucifer " , Age = 26 }
; Stopwatch sw1
=
new
Stopwatch(); sw1.Start();
for
(
int
i
=
0
; i
<
10000000
;
++
i)
...
{ val = QuickAccess < User > .Get_ProperyVal < int > (user, " Age " ); }
sw1.Stop(); Console.WriteLine(sw1.ElapsedMilliseconds);
虽然这段代码不太实用不过能体现出Linq和Expression的强大,谢谢观看。