15.1 查询表达式的概念
15.2 查询表达式作为方法调用
简单的查询表达式
- private static void ShowContextualKeywords1()
- {
- IEnumerable<string> selection = from word in Keywords
- where !word.Contains(‘*‘)
- select word;
- foreach (string keyword in selection)
- {
- Console.Write(" " + keyword);
- }
- }
- private static string[] Keywords = {
- "abstract", "add*", "alias*", "as", "ascending*", "base",
- "bool", "break", "by*", "byte", "case", "catch", "char",
- "checked", "class", "const", "continue", "decimal",
- "default", "delegate", "descending*", "do", "double",
- "dynamic*", "else", "enum", "event", "equals*",
- "explicit", "extern", "false", "finally", "fixed",
- "from*", "float", "for", "foreach", "get*", "global*",
- "group*", "goto", "if", "implicit", "in", "int",
- "into*", "interface", "internal", "is", "lock", "long",
- "join*", "let*", "namespace", "new", "null", "object",
- "on*", "operator", "orderby*", "out", "override",
- "params", "partial*", "private", "protected", "public",
- "readonly", "ref", "remove*", "return", "sbyte", "sealed",
- "select*", "set*", "short", "sizeof", "stackalloc",
- "static", "string", "struct", "switch", "this", "throw",
- "true", "try", "typeof", "uint", "ulong", "unchecked",
- "unsafe", "ushort", "using", "value*", "var*", "virtual",
- "void", "volatile", "where*", "while", "yield*"
- };
15.1.1 投射
查询表达式输出是一个IEnumerbale<T>或IQueryable<T>集合。T数据类型是从select或者groupby子句推导。
上例string数据类型是从 select word 推导的,因为word是一个字符串。word数据类型是由from子句所指定的IEnumerbale<T>集合的类型参数(这里是Keywords)。由于Keywords是一个string数组,它实现了IEnumerbale<T>,所以word是一个字符串。
表达式查询特定类型集合时,结果允许将数据投射成一个完全不同的类型。
Directory.GetCurrentDirectory()
- public static void Main()
- {
- List1(Directory.GetCurrentDirectory(),"*");
- }
- static void List1(string rootDirectory, string searchPattern)
- {
- IEnumerable<FileInfo> files =
- from fileName in Directory.GetFiles(
- rootDirectory, searchPattern)
- select new FileInfo(fileName);
- foreach (FileInfo file in files)
- {
- Console.WriteLine(".{0} ({1})",
- file.Name, file.LastWriteTime);
- }
- }
这里返回的是一个IEnumerable<FileInfo>,而不是System.IO.Directory.GetFiles()返回的IEnumerables<string>数据类型。
C#3.0引入匿名类型,很大程度上就是利用像这样的“投射”功能。
- var files =
- from fileName in Directory.GetFiles(
- rootDirectory, searchPattern)
- select new FileInfo(fileName);
15.1.2 筛选
where子句在垂直方向筛选集合。
- IEnumerable<string> selection = from word in Keywords
- where !word.Contains(‘*‘)
- select word;
15.1.3 排序
在查询表达式中对数据进行排序的是 orderby 子句。
- IEnumerable<string> fileNames =
- from fileName in Directory.GetFiles(
- rootDirectory, searchPattern)
- orderby (new FileInfo(fileName)).Length descending,
- fileName
- select fileName;
ascending和descending是上下文关键字,分别是升序或降序排序。
15.1.4 let子句
下面代码与上面的代码相似。问题是FileInfo要创建两次,分别在orderby 和 select子句中创建。
- public static void Main()
- {
- ListByFileSize2(Directory.GetCurrentDirectory(), "*");
- }
- static void ListByFileSize2(
- string rootDirectory, string searchPattern)
- {
- IEnumerable<FileInfo> files =
- from fileName in Directory.GetFiles(
- rootDirectory, searchPattern)
- orderby new FileInfo(fileName).Length, fileName
- select new FileInfo(fileName);
- foreach (FileInfo file in files)
- {
- // As simplification, current directory is
- // assumed to be a subdirectory of
- // rootDirectory
- string relativePath = file.FullName.Substring(
- Environment.CurrentDirectory.Length);
- Console.WriteLine(".{0}({1})",
- relativePath, file.Length);
- }
- }
可以用let子句避免这种昂贵的开销。
- IEnumerable<FileInfo> files =
- from fileName in Directory.GetFiles(
- rootDirectory, searchPattern)
- let file = new FileInfo(fileName)
- orderby file.Length, fileName
- select file;
- let子句引入了一个新的范围变量
- 它容纳的表达式值可以在查询表达式剩余部分使用
- 可以添加任意数量的let表达式,只需要它们每一个作为一个附加的子句
- 放在第一个from子句之后,最后一个select/group by子句之前,加入查询即可
15.1.5 分组
SQL中涉及对数据项进行聚合以生成一个汇总或合计或其他聚合值。
LINQ中表达力更强,LINQ允许将单独的项分组到一系列子集合中,还允许那些组与所查的集合中项关联
- private static void GroupKeywords1()
- {
- IEnumerable<IGrouping<bool, string>> selection =
- from word in keyWords
- group word by word.Contains(‘*‘);
- foreach (IGrouping<bool, string> wordGroup
- in selection)
- {
- Console.WriteLine(Environment.NewLine + "{0}:",
- wordGroup.Key ?
- "Contextual Keywords" : "Keywords");
- foreach (string keyword in wordGroup)
- {
- Console.Write(" " +
- (wordGroup.Key ?
- keyword.Replace("*", null) : keyword));
- }
- }
- }
结果 :
查询结果是一系列IGrouping<bool,?string>类型元素。
查询生成一系列分组,将相同的bool类型键应用于组内的每个string。
在group子句后面选择一个匿名类型
- private static void GroupKeywords1()
- {
- IEnumerable<IGrouping<bool, string>> keywordGroups =
- from word in keyWords
- group word by word.Contains(‘*‘);
- var selection = from groups in keywordGroups
- select new
- {
- IsContextualKeyword = groups.Key,
- Items = groups
- };
- foreach (var wordGroup in selection)
- {
- Console.WriteLine(Environment.NewLine + "{0}:",
- wordGroup.IsContextualKeyword ?
- "Contextual Keywords" : "Keywords");
- foreach (var keyword in wordGroup.Items)
- {
- Console.Write(" " +
- keyword.Replace("*", null));
- }
- }
- }
IGrouping<TKey,TElement>.Key 重命名为IsContextualKeyword,并命名了子集合属性Items。有人人为可以在匿名类型中添加一个属性来标识数据项的个数,然后,这个功能由wordGroup.Items.Count()提供。
15.1.6 使用into进行查询延续