随笔-51  评论-726  文章-1  trackbacks-0
  2010年5月26日

 

目录

.Net4 Expression Tree 入门(1): Hello World!

.Net4 Expression Tree 入门(2): IfThen, SwitchCase

.Net4 Expression Tree 入门(3): Loop 循环

 

前面已经介绍了.Net4 Expression Tree的分支与循环,是时候综合起来写一个稍微复杂一点的实例了。

求N以内的所有质数

一般的写法
static List<int> GetPrimes_SimpleMethod(int to)
{
    var res = new List<int>();
    for (int n = 2; n <= to; n++)
    {
        bool found = false;

        for (int d = 2; d <= Math.Sqrt(n); d++)
        {
            if (n % d == 0)
            {
                found = true;
                break;
            }
        }

        if (!found)
            res.Add(n);
    }
    return res;
}

 

暂且不用考虑以上算法的时间复杂度、性能什么的,因为只是为了学习 Expression Tree 而已。之前都说过,Expression 里是没有For这些常用方法的,只有Loop,因此为了更方便构造 Expression Tree, 需要对上面代码稍微修改成没for的形式。

for (int n = 2; n <= to; n++)
{
    // do sth…
}

改成 while形式:

int n = 2;
while (true)
{
    if (!(n <= to))
        break;
    // do sth…
    n++;
}
求N以内的所有质数的“NoFor” 写法

【纯粹是为了更方便构造 Expression Tree,否则相信没人用while(true)这样写法】

static List<int> GetPrimes_NoFor(int to)
{
    var res = new List<int>();
    int n = 2;
    while (true)
    {
        if (!(n <= to))
            break;
        bool found = false;

        int d = 2;
        while (true)
        {
            if (!(d <= Math.Sqrt(n)))
                break;

            if (n % d == 0)
            {
                found = true;
                break;
            }

            d++;
        }

        if (!found)
            res.Add(n);

        n++;
    }
    return res;
}

 

上述代码与表达式的对比列表

原始代码

表达式

var res = new List<int>();
Expression.Assign(
    res,
    Expression.New(typeof(List<int>))
)
int n = 2;
Expression.Assign(
    n,
    Expression.Constant(2)
)
while (true)
{
    if (!(n <= to))
        break;
Expression.Loop(
    Expression.Block(
        Expression.IfThen(
            Expression.Not(
                Expression.LessThanOrEqual(
                    n,
                    to
                )
            ),
            Expression.Break(breakOuter)
        )
Math.Sqrt(n)
Expression.Call(
    null,
    typeof(Math).GetMethod("Sqrt"),
    Expression.Convert(
        n,
        typeof(double)
    )
)
d++;
Expression.PostIncrementAssign(d)
res.Add(n);
Expression.Call(
    res,
    typeof(List<int>).GetMethod("Add"),
    n
)

 

最终构建表达式的代码很长,有兴趣的不妨自己试着写写,这里不贴上来,可以参考这篇外文STATEMENT TREES WITH LESS PAIN – FOLLOW-UP ON SYSTEM.LINQ.EXPRESSIONS V4.0》。

你是否也因为Expression 里没有for这个方法而感到不爽?一切循环都得改成loop这种形式?Expression构建是不是很麻烦罗嗦?为什么Expression一切方法皆是static的…等等。

如果改成下面这种形式会不会好点?

原始代码

表达式

var res = new List<int>();
res.Assign(Expression.New(typeof(List<int>)))
int n = 2;
n.Assign(2)
n ++;
n.PostIncrementAssign()
for (int n = 2; n <= to; n++)
Expression.For(n, n.Assign(2), n <= to, n.PostIncrementAssign()
res.Add(n); res.Method("Add", n)

 

这样会不会更简洁?欢迎作进一步交流。我会在下一篇随笔里分析如何实现以上形式的写法。

posted @ 2010-05-26 14:59 CoolCode 阅读(1576) 评论(0) 编辑

 

为什么我需要 Expression Tree?

它有什么好处?

实际项目中有可能用到它么?

它可以应用在哪些地方?

… …

以上是很多不认识Expression Tree,或刚接触不久的童鞋们所困惑的问题。实际上,上面这些问题在他们心中只是归纳成一个问题——Expression Tree 值不值得我去学?

 

于是乎,大多数技术诞生时都会伴随着Showcase,Getting Started,Tutorial,Sample Application等。大学某些导师就是没有得这一窍门,在开课的第一天没有花时间去展示他所教导的课程的Showcase,以至于童鞋们感到very boring,没有动力学下去。关于这一点,当初教导我编程语言的老师经过一段时间后明白了。她在开课前一个月都是讲语法,什么if else for while 啊,发现童鞋们睡倒一大片。于是,她用她所教导的语言编写了几个图形游戏,如打乒乓球之类的。那一堂课,童鞋们专心多了,而我也知道编程不只用于加减乘除了。

Showcase For Expression Tree

严格来说,Expression Tree 是个低调的家伙,以至于它的光芒被其他上层建筑挡住了,如Linq to SQL。因此,也很难找到能让大家眼前一亮的Showcase,而只能限于代码级别去展示。

Case 1: Linq to SQL 动态查询
var queryBuilder = QueryBuilder.Create<Order>()
    .Like(c => c.Customer.ContactName, txtCustomer.Text)
    .Between(c => c.OrderDate, DateTime.Parse(txtDateFrom.Text), DateTime.Parse(txtDateTo.Text))
    .Equals(c => c.EmployeeID, int.Parse(ddlEmployee.SelectedValue))
    .In(c => c.ShipCountry, selectedCountries); 

详见 QueryBuilder : 打造优雅的Linq To SQL动态查询

更多 Google 一下 Linq to SQL 动态查询

Case 2:打造 Linq Provider

Linq to Google 示例代码

GoogleContext gc = new GoogleContext(key);
var r = from ipods in gc.products
        where ipods.BaseQuery == "mp3 players" && ipods.Brand == "apple" && ipods.FeedType == "snippets" && ipods.Price < 200
        orderby ipods.Price
        select new { ipods.Title, ipods.Price };

更多 Walkthrough: Creating an IQueryable LINQ Provider

Google 一下 Linq Provider

Case 3:动态代码、动态编译、动态组件
var c = new CodeDomGenerator();

c.AddNamespace("Samples").AddClass("TestClass")
   .AddMethod(MemberAttributes.Public | MemberAttributes.Static, () => "Print",
       Emit.stmt(() => Console.WriteLine("Hello, world!"))
);

Console.WriteLine(c.GenerateCode(CodeDomGenerator.Language.CSharp));
Console.WriteLine(c.GenerateCode(CodeDomGenerator.Language.VB));

Assembly assembly = c.Compile();

详看Expressions to CodeDOM

 

以上示例代码都见不到 Expression Tree 的影子,因为 Expression Tree 是支撑物,默默地成为伟大建筑的一根支柱。

以上示例代码并不是说非用 Expression Tree 不可,底层实现方法有很多,Expression Tree 只是其中一种。

结论

Expression Tree 永远不会孤军作战的, 正如一根支柱不会独立存在那样。

posted @ 2010-05-26 12:14 CoolCode 阅读(2639) 评论(17) 编辑