写程序,不可避免要控制程序的流程,像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#高效编程》