使用查询语法而不是循环

      写程序,不可避免要控制程序的流程,像for, while, do/while, foreach,计算机语言的设计者都为我们提供了这些重要的循环结构,但是,这些控制结构都是属于“命令式”的,也就是说,你要告诉程序怎么去做。不过,我们拥有比循环更好的选择,这就是查询语法。与循环结构相比,查询语法属于“声明式”,你只需告诉程序,你想做什么,至于怎么做,交给程序就可以了。

 

1. 更清楚的表示你的意图

我们先来看一段采用循环的代码:

 

	   int[] foo = new int[100];
            for (int num = 0; num < foo.Length; num++)
            {
                foo[num] = num*num;
            }

            foreach (int i in foo)
            {
                Console.WriteLine(i.ToString());
            }

 

这是一段非常简单的代码,我们可以发现,我们关注了太多的细节实现。如果采用“声明式”的查询语法:

 

	   int[] foo = (from n in Enumerable.Range(0, 100)
                         select n*n).ToArray();
            foo.ForAll((n) => Console.WriteLine(n.ToString()));

 

显然,代码的可读性增强了,同时也更加易于重用。

 

2. 复杂的问题依旧保持简单的书写方式

 

假设我们要用0~99的整数生成所有的(X,Y)二元组,同时要求X+Y<100,最后,按照生成的点距离原点的距离逆序排列。

如果采用循环的方式:

 

	private static IEnumerable<Tuple<int,int>> ProduceIndices()
        {
            var storage = new List<Tuple<int, int>>();

            for (int x = 0; x < 100; x++)
            {
                for (int y = 0; y < 100; y++)
                {
                    if (x + y < 100)
                    {
                        storage.Add(Tuple.Create(x,y));
                    }
                }
            }

            storage.Sort((point1,poing2)=>(poing2.Item1*poing2.Item1+poing2.Item2*poing2.Item2).CompareTo(
                point1.Item1*point1.Item1+point1.Item2*point1.Item2));
            return storage;
        }

 

何等“复杂”的一段代码!

我们再来看看使用查询语法的代码:

 

	private static IEnumerable<Tuple<int,int>> QueryIndices()
        {
            return from x in Enumerable.Range(0, 100)
                   from y in Enumerable.Range(0, 100)
                   where x + y < 100
                   orderby (x*x + y*y) descending
                   select Tuple.Create(x, y);
        }

 

负责的问题,通过声明式的查询语法,我们依旧可以保持简单、优雅的代码。

 

3. 性能比较

相对于普通的循环,查询语法经常被提起的一个问题是性能问题。虽然我们可以很容易的设计一个比查询语法性能更加高的循环,但是,问题的关键是我们需要判断,某个特别的情况下,某个查询的效率是不是有问题。

例如,我们将#2的例子的100改成1000,然后对比二者的性能会发现,查询语法的性能反而更高。

 

总结:

当我们需要编写循环的时候,首先要看能否用查询语法实现,如若不能,那么再看是否可以用方法调用(相对于查询语法,如LINQ有查询语法和方法调用2种方式)来代替。这样,我们写出来的代码会比循环结构更简洁一些。

 

参考:《C#高效编程》

posted @ 2012-06-17 19:50  Xiao Tian  阅读(277)  评论(0编辑  收藏  举报