今天看《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 } };
非常簡單是吧,接下來只要把他用Expression翻譯一下,並編成泛型的就可以了。代碼如下:
var val = books.Select(book => book.Name).First();
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的強大,謝謝觀看。