Expression Tree
前言
從C#3.0開始可以使用 Expression trees 來取得 object的 type, members等等...的功能。
那這個跟func有什麼差別呢? 在這邊舉個例子
static void Main(string[] args)
{
string result = MyFunc(x => x.Name);
Console.WriteLine(result); //Print : Shoes
}
private static string MyFunc(Func<Product, object> func)
{
var product = new Product()
{
Id = 1,
Name = "Shoes",
Price = 1000
};
return func(product).ToString();
}
這個簡單的例子,可以指定我要取得Name 這個Property 的值。 在這邊我們只能知道他是傳哪一個Property,那如果我要取得Property名稱呢? 單純用Func是沒辦法做到的,要另外加上Expression的用法。
static void Main(string[] args)
{
string result = MyFunc(x => x.Name);
Console.WriteLine(result); //Print : Name
}
private static string MyFunc(Expression<Func<Product, object>> e)
{
Expression expression = e.Body;
if (expression is MemberExpression)
{
var member = expression as MemberExpression;
return member.Member.Name;
}
return string.Empty;
}
只要這樣寫,就可以取得Property Name了,那如果要在Expression取得值得話,只要把Expression compile成Func就可以了,範例如下:
static void Main(string[] args)
{
string result = MyFunc(x => x.Name);
Console.WriteLine(result); //Print : Name = Shoes
}
private static string MyFunc(Expression<Func<Product, object>> e)
{
Expression expression = e.Body;
if (expression is MemberExpression)
{
var product = new Product()
{
Id = 1,
Name = "Shoes",
Price = 1000
};
var member = expression as MemberExpression;
//Compile成func
Func<Product, object> func = e.Compile();
var value = func(product);
return $"{member.Member.Name} = {value}";
}
return string.Empty;
}
Expression 根據不同的存取方式會有不同的NodeType 例如 MyFunc(x => "test")遇到這種情形,就要去判斷NodeType來決定後面要怎麼處理,範例如下:
static void Main(string[] args)
{
string result = MyFunc(x => "test");
Console.WriteLine(result); //Print : test
}
private static string MyFunc(Expression<Func<Product, object>> e)
{
Expression expression = e.Body;
if (expression.NodeType == ExpressionType.Constant)
{
var constant = expression as ConstantExpression;
return constant.Value.ToString();
}
return string.Empty;
}
最後介紹今天要介紹的另一種,也是很重要的一種NodeType,ExpressionType.Convert。當我們傳入MyFunc(x => x.Price)的時候,因為Price是value type decimal 所以會boxing(轉型)成object,因為有轉型的動作,所以做法上跟MyFunc(x => x.Name)不太一樣,範例如下:
static void Main(string[] args)
{
string result = MyFunc(x => x.Price);
Console.WriteLine(result); //Print : Price
}
private static string MyFunc(Expression<Func<Product, object>> e)
{
Expression expression = e.Body;
if (expression.NodeType == ExpressionType.Convert)
{
var unary = expression as UnaryExpression;
var member = unary.Operand as MemberExpression;
return member.Member.Name;
}
return string.Empty;
}
小結
Expression Tree基本用法,大致上就是這樣,至於能用在什麼地方,我想最常用的地方應該就是寫自訂的Html Helper了吧。
參考:
一天一分享,身體好健康。
該追究的不是過去的原因,而是現在的目的。