C#中的LINQ?to?Objects詳解(2)
相關(guān)文章:
四、Linq和反射
.NET Framework 類庫(kù)反射 API 可用于檢查 .NET 程序集中的元數(shù)據(jù),以及創(chuàng)建位于該程序集中的類型、類型成員、參數(shù)等等的集合。 因?yàn)檫@些集合支持泛型 IEnumerable 接口,所以可以使用 LINQ 查詢它們。
下面的示例演示了如何將 LINQ 與反射配合使用以檢索有關(guān)與指定搜索條件匹配的方法的特定元數(shù)據(jù)。 在這種情況下,該查詢將在返回?cái)?shù)組等可枚舉類型的程序集中查找所有方法的名稱。
該示例使用 GetTypes 方法返回指定程序集中的類型的數(shù)組。 將應(yīng)用 where 篩選器,以便僅返回公共類型。 對(duì)于每個(gè)公共類型,子查詢使用從 GetMethods 調(diào)用返回的 MethodInfo 數(shù)組生成。 篩選這些結(jié)果,以僅返回其返回類型為數(shù)組或?qū)崿F(xiàn) IEnumerable 的其他類型的方法。 最后,通過(guò)使用類型名稱作為鍵來(lái)對(duì)這些結(jié)果進(jìn)行分組。
Assembly assembly = Assembly.Load("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken= b77a5c561934e089"); var pubTypesQuery = from type in assembly.GetTypes() where type.IsPublic from method in type.GetMethods() where method.ReturnType.IsArray == true || (method.ReturnType.GetInterface(typeof(System.Collections.Generic.IEnumerable<>).FullName) != null && method.ReturnType.FullName != "System.String") group method.ToString() by type.ToString(); foreach (var groupOfMethods in pubTypesQuery) { Console.WriteLine("Type: {0}", groupOfMethods.Key); foreach (var method in groupOfMethods) { Console.WriteLine(" {0}", method); } } Console.WriteLine("Press any key to exit");
五、LINQ 和字符串
1、LINQ 和文件目錄
許多文件系統(tǒng)操作實(shí)質(zhì)上是查詢,因此非常適合使用 LINQ 方法。
本部分中的查詢是非破壞性查詢。 它們不用于更改原始文件或文件夾的內(nèi)容。 這遵循了查詢不應(yīng)引起任何副作用這條規(guī)則。 通常,修改源數(shù)據(jù)的任何代碼(包括執(zhí)行創(chuàng)建/更新/刪除運(yùn)算符的查詢)應(yīng)與只查詢數(shù)據(jù)的代碼分開(kāi)。
實(shí)例1、如何查詢具有指定屬性或名稱的文件
此示例演示如何查找指定目錄樹(shù)中具有指定文件擴(kuò)展名(例如“.txt”)的所有文件,還演示如何根據(jù)創(chuàng)建時(shí)間返回樹(shù)中最新或最舊的文件。
//該查詢將所有生產(chǎn)的完整路徑。txt文件指定的文件夾包括子文件夾下。 const string path = @"C:\Program Files (x86)\Microsoft Visual Studio 14.0\"; //取文件系統(tǒng)快照 var dir = new DirectoryInfo(path); //該方法假定應(yīng)用程序在指定路徑下的所有文件夾都具有搜索權(quán)限。 var files = dir.GetFiles("*.*", SearchOption.AllDirectories); //創(chuàng)建查詢 var fileQuery = from file in files where file.Extension == ".html" orderby file.Name select file; //執(zhí)行查詢 foreach (var file in fileQuery) { Console.WriteLine(file.FullName); } //創(chuàng)建和執(zhí)行一個(gè)新的查詢,通過(guò)查詢舊文件的創(chuàng)建時(shí)間作為一個(gè)出發(fā)點(diǎn) //Last:選最后一個(gè),因?yàn)槭前慈掌谏?,所以最新的是指最后一個(gè) var newestFile = (from file in fileQuery orderby file.CreationTime select new { file.FullName, file.CreationTime }) .Last(); Console.WriteLine($"\r\nThe newest .txt file is {newestFile.FullName}. Creation time: {newestFile.CreationTime}");
實(shí)例2、如何按照擴(kuò)展名對(duì)文件進(jìn)行分組
此示例演示如何使用 LINQ 對(duì)文件或文件夾列表執(zhí)行高級(jí)分組和排序操作。此外,它還演示如何使用 Skip 和 Take 方法對(duì)控制臺(tái)窗口中的輸出進(jìn)行分頁(yè)。
下面的查詢演示如何按文件擴(kuò)展名對(duì)指定目錄樹(shù)的內(nèi)容進(jìn)行分組。
const string path = @"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7"; //“path”的長(zhǎng)度,后續(xù)用于在輸出時(shí)去掉“path”這段前綴 var trimLength = path.Length; //取文件系統(tǒng)快照 var dir = new DirectoryInfo(path); //該方法假定應(yīng)用程序在指定路徑下的所有文件夾都具有搜索權(quán)限。 var files = dir.GetFiles("*.*", SearchOption.AllDirectories); //創(chuàng)建查詢 var query = from file in files group file by file.Extension.ToLower() into fileGroup orderby fileGroup.Key select fileGroup; //一次顯示一組。如果列表實(shí)體的行數(shù)大于控制臺(tái)窗口中的行數(shù),則分頁(yè)輸出。 PageOutput(trimLength, query); private static void PageOutput(int rootLength, IOrderedEnumerable<string, FileInfo>> query) { //跳出分頁(yè)循環(huán)的標(biāo)志 var isAgain = true; //控制臺(tái)輸出的高度 var numLines = Console.WindowHeight - 3; //遍歷分組集合 foreach (var g in query) { var currentLine = 0; do { Console.Clear(); Console.WriteLine(string.IsNullOrEmpty(g.Key) ? "[None]" : g.Key); //從“currentLine”開(kāi)始顯示“numLines”條數(shù) var resultPage = g.Skip(currentLine).Take(numLines); //執(zhí)行查詢 foreach (var info in resultPage) { Console.WriteLine("\t{0}", info.FullName.Substring(rootLength)); } //記錄輸出行數(shù) currentLine += numLines; Console.WriteLine("點(diǎn)擊“任意鍵”繼續(xù),按“End”鍵退出"); //給用戶選擇是否跳出 var key = Console.ReadKey().Key; if (key != ConsoleKey.End) continue; isAgain = false; break; } while (currentLine < g.Count()); if (!isAgain) { break; } } }
為了使您可以查看所有結(jié)果,此示例還演示如何按頁(yè)查看結(jié)果。這些方法可應(yīng)用于 Windows 和 Web 應(yīng)用程序。
請(qǐng)注意,由于代碼將對(duì)組中的項(xiàng)進(jìn)行分頁(yè),因此需要嵌套的 foreach 循環(huán)。此外,還會(huì)使用某他某個(gè)邏輯來(lái)計(jì)算列表中的當(dāng)前位置,以及使用戶可以停止分頁(yè)并退出程序。在這種特定情況下,將針對(duì)原始查詢的緩存結(jié)果運(yùn)行分頁(yè)查詢。
實(shí)例3、如何查詢一組文件夾中的總字節(jié)數(shù)
此示例演示如何檢索指定文件夾及其所有子文件夾中的所有文件所使用的總字節(jié)數(shù)。
Sum 方法添加在 select 子句中選擇的所有項(xiàng)的值。您可以輕松修改此查詢以檢索指定目錄樹(shù)中的最大或最小文件,方法是調(diào)用 Min 或 Max 方法,而不是 Sum。
const string path = @"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC#"; var dir = new DirectoryInfo(path); var files = dir.GetFiles("*.*", SearchOption.AllDirectories); var query = from file in files select file.Length; //緩存結(jié)果,以避免多次訪問(wèn)文件系統(tǒng) var fileLengths = query as long[] ?? query.ToArray(); //返回最大文件的大小 var largestLength = fileLengths.Max(); //返回指定文件夾下的所有文件中的總字節(jié)數(shù) var totalBytes = fileLengths.Sum(); Console.WriteLine(); Console.WriteLine("There are {0} bytes in {1} files under {2}",totalBytes, files.Count(), path); Console.WriteLine("The largest files is {0} bytes.", largestLength);
如果您只需要統(tǒng)計(jì)特定目錄樹(shù)中的字節(jié)數(shù),則可以更高效地實(shí)現(xiàn)此目的,而無(wú)需創(chuàng)建 LINQ 查詢,因?yàn)樵摬樵儠?huì)引發(fā)創(chuàng)建列表集合作為數(shù)據(jù)源的系統(tǒng)開(kāi)銷。隨著查詢復(fù)雜度的增加,或者當(dāng)您必須對(duì)同一數(shù)據(jù)源運(yùn)行多個(gè)查詢時(shí),LINQ 方法的有用性也會(huì)隨之增加。
實(shí)例4、如何比較兩個(gè)文件夾中的內(nèi)容
此示例演示比較兩個(gè)文件列表的三種方法:
- (1)查詢一個(gè)指定兩個(gè)文件列表是否相同的布爾值;
- (2)查詢用于檢索同時(shí)位于兩個(gè)文件夾中的文件的交集;
- (3)查詢用于檢索位于一個(gè)文件夾中但不在另一個(gè)文件夾中的文件的差集;
//創(chuàng)建兩個(gè)帶比較的文件夾 const string path1 = @"E:\Test1"; const string path2 = @"E:\Test2"; var dir1 = new DirectoryInfo(path1); var dir2 = new DirectoryInfo(path2); //取文件快照 var files1 = dir1.GetFiles("*.*", SearchOption.AllDirectories); var files2 = dir2.GetFiles("*.*", SearchOption.AllDirectories); //自定義文件比較器 var comparer = new FileComparer(); //該查詢確定兩個(gè)文件夾包含相同的文件列表,基于自定義文件比較器。查詢立即執(zhí)行,因?yàn)樗祷匾粋€(gè)bool。 var areIdentical = files1.SequenceEqual(files2, comparer); Console.WriteLine(areIdentical == true ? "the two folders are the same" : "The two folders are not the same"); //交集:找相同的文件 var queryCommonFiles = files1.Intersect(files2, comparer); var commonFiles = queryCommonFiles as FileInfo[] ?? queryCommonFiles.ToArray(); if (commonFiles.Any()) { Console.WriteLine("The following files are in both folders:"); foreach (var v in commonFiles) { Console.WriteLine(v.FullName); } } else { Console.WriteLine("There are no common files in the two folders."); } //差集:對(duì)比兩個(gè)文件夾的差異 var diffQuery = files1.Except(files2, comparer); Console.WriteLine("The following files are in list1 but not list2:"); foreach (var v in diffQuery) { Console.WriteLine(v.FullName); } //該實(shí)現(xiàn)定義了一個(gè)非常簡(jiǎn)單的兩個(gè) FileInfo 對(duì)象之間的比較。它只比較文件的名稱和它們字節(jié)數(shù)的長(zhǎng)度 public class FileComparer : IEqualityComparer { public bool Equals(FileInfo x, FileInfo y) { return string.Equals(x.Name, y.Name, StringComparison.CurrentCultureIgnoreCase) && x.Length == y.Length; } //返回一個(gè)比較標(biāo)準(zhǔn)的哈希值。根據(jù) IEqualityComparer 規(guī)則,如果相等,那么哈希值也必須是相等的。 //因?yàn)檫@里所定義的相等只是一個(gè)簡(jiǎn)單的值相等,而不是引用標(biāo)識(shí),所以兩個(gè)或多個(gè)對(duì)象將產(chǎn)生相同的哈希值是可能的。 public int GetHashCode(FileInfo obj) { var s = string.Format("{0}{1}", obj.Name, obj.Length); return s.GetHashCode(); } }
【注意】 可以修改上述這些方法以便對(duì)任意類型的對(duì)象序列進(jìn)行比較。
此處顯示的 FileComparer 類演示如何將自定義比較器類與標(biāo)準(zhǔn)查詢運(yùn)算符一起使用。該類不是為在實(shí)際方案中使用而設(shè)計(jì)的。它只是使用每個(gè)文件的名稱和長(zhǎng)度(以字節(jié)為單位)來(lái)確定每個(gè)文件夾的內(nèi)容是否相同。在實(shí)際方案中,應(yīng)對(duì)此比較器進(jìn)行修改以執(zhí)行更嚴(yán)格的相等性檢查。
實(shí)例5、如何在目錄樹(shù)中查詢最大的文件
此示例演示與文件大小(以字節(jié)為單位)相關(guān)的五種查詢:
- 如何檢索最大文件的大?。ㄒ宰止?jié)為單位);
- 如何檢索最小文件的大?。ㄒ宰止?jié)為單位);
- 如何從指定的根文件夾下的一個(gè)或多個(gè)文件夾檢索 FileInfo 對(duì)象最大或最小文件;
- 如何檢索一個(gè)序列,如 10 個(gè)最大文件。
下面的示例包含五種不同的查詢,這些查詢演示如何根據(jù)文件大?。ㄒ宰止?jié)為單位)查詢和分組文件??梢暂p松地修改這些示例,以使查詢基于 FileInfo對(duì)象的某個(gè)其他屬性。
const string path = @"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC#"; var dir = new DirectoryInfo(path); var files = dir.GetFiles("*.*", SearchOption.AllDirectories); var query = from file in files select file.Length; //返回最大文件的大小 var maxSize = query.Max(); Console.WriteLine("The length of the largest file under {0} is {1}",path, maxSize); //倒序排列 var query2 = from file in files let len = file.Length where len > 0 orderby len descending select file; var fileInfos = query2 as FileInfo[] ?? query2.ToArray(); //倒序排列的第一個(gè)就是最大的文件 var longestFile = fileInfos.First(); //倒序排列的第一個(gè)就是最小的文件 var smallestFile = fileInfos.Last(); Console.WriteLine("The largest file under {0} is {1} with a length of {2} bytes", path, longestFile.FullName, longestFile.Length); Console.WriteLine("The smallest file under {0} is {1} with a length of {2} bytes", path, smallestFile.FullName, smallestFile.Length); Console.WriteLine("===== The 10 largest files under {0} are: =====", path); //返回前10個(gè)最大的文件 var queryTenLargest = fileInfos.Take(10); foreach (var v in queryTenLargest) { Console.WriteLine("{0}: {1} bytes", v.FullName, v.Length); }
若要返回一個(gè)或多個(gè)完整的 FileInfo 對(duì)象,查詢必須首先檢查數(shù)據(jù)源中的每個(gè)對(duì)象,然后按這些對(duì)象的 Length 屬性的值排序它們。然后查詢可以返回具有最大長(zhǎng)度的單個(gè)對(duì)象或序列。使用 First 可返回列表中的第一個(gè)元素。使用 Take 可返回前 n 個(gè)元素。指定降序排序順序可將最小的元素放在列表的開(kāi)頭。
實(shí)例6、如何在目錄樹(shù)中查詢重復(fù)的文件
有時(shí),多個(gè)文件夾中可能存在同名的文件。例如,在 Visual Studio 安裝文件夾中,有多個(gè)文件夾包含 readme.htm 文件。
此示例演示如何在指定的根文件夾中查詢這樣的重復(fù)文件名。
第二個(gè)示例演示如何查詢其大小和創(chuàng)建時(shí)間也匹配的文件。
static void Main(string[] args) { QueryDuplicates(); //QueryDuplicates2(); Console.ReadKey(); } static void QueryDuplicates() { const string path = @"C:\Program Files (x86)\Microsoft Visual Studio 12.0"; var dir = new DirectoryInfo(path); var files = dir.GetFiles("*.*", SearchOption.AllDirectories); var charsToSkip = path.Length; var queryDupNames = (from file in files group file.FullName.Substring(charsToSkip) by file.Name into fileGroup where fileGroup.Count() > 1 select fileGroup).Distinct(); PageOutput<string, string>(queryDupNames); } private static void QueryDuplicates2() { const string path = @"C:\Program Files (x86)\Microsoft Visual Studio 12.0"; var dir = new DirectoryInfo(path); var files = dir.GetFiles("*.*", SearchOption.AllDirectories); //路徑的長(zhǎng)度 var charsToSkip = path.Length; //注意一個(gè)復(fù)合鍵的使用。三個(gè)屬性都匹配的文件屬于同一組。 //匿名類型也可以用于復(fù)合鍵,但不能跨越方法邊界。 var queryDupFiles = from file in files group file.FullName.Substring(charsToSkip) by new PortableKey() { Name = file.Name, CreationTime = file.CreationTime, Length = file.Length } into fileGroup where fileGroup.Count() > 1 select fileGroup; var queryDupNames = queryDupFiles as IGroupingstring>[] ?? queryDupFiles.ToArray(); var list = queryDupNames.ToList(); var i = queryDupNames.Count(); //分頁(yè)輸出 PageOutputstring>(queryDupNames); } private static void PageOutput(IEnumerable> queryDupNames) { //跳出分頁(yè)循環(huán)的標(biāo)志 var isAgain = true; var numLines = Console.WindowHeight - 3; var dupNames = queryDupNames as IGrouping[] ?? queryDupNames.ToArray(); foreach (var queryDupName in dupNames) { //分頁(yè)開(kāi)始 var currentLine = 0; do { Console.Clear(); Console.WriteLine("Filename = {0}", queryDupName.Key.ToString() == string.Empty ? "[none]" : queryDupName.Key.ToString()); //跳過(guò) currentLine 行,取 numLines 行 var resultPage = queryDupName.Skip(currentLine).Take(numLines); foreach (var fileName in resultPage) { Console.WriteLine("\t{0}", fileName); } //增量器記錄已顯示的行數(shù) currentLine += numLines; //讓用戶自動(dòng)選擇下一下 //Console.WriteLine("Press any key to continue or the 'End' key to break..."); //var key = Console.ReadKey().Key; //if (key == ConsoleKey.End) //{ // isAgain = false; // break; //} //按得有點(diǎn)累,還是讓它自動(dòng)下一頁(yè)吧 Thread.Sleep(100); } while (currentLine < queryDupName.Count()); //if (!isAgain) // break; } }
第一個(gè)查詢使用一個(gè)簡(jiǎn)單的鍵確定是否匹配;這會(huì)找到同名但內(nèi)容可能不同的文件。第二個(gè)查詢使用復(fù)合鍵并根據(jù) FileInfo 對(duì)象的三個(gè)屬性來(lái)確定是否匹配。此查詢非常類似于查找同名且內(nèi)容類似或相同的文件。
實(shí)例7、如何在文件夾中查詢文件的內(nèi)容
此示例演示如何查詢指定目錄樹(shù)中的所有文件、打開(kāi)每個(gè)文件并檢查其內(nèi)容。 此類技術(shù)可用于對(duì)目錄樹(shù)的內(nèi)容創(chuàng)建索引或反向索引。 此示例中執(zhí)行的是簡(jiǎn)單的字符串搜索。 但是,可使用正則表達(dá)式執(zhí)行更復(fù)雜類型的模式匹配。
const string path = @"C:\Program Files (x86)\Microsoft Visual Studio 12.0"; var dir = new DirectoryInfo(path); var files = dir.GetFiles("*.*", SearchOption.AllDirectories); //待匹配的字符串 const string searchTerm = @"Visual Studio"; //搜索每個(gè)文件的內(nèi)容。 //您也可以使用正則表達(dá)式替換 Contains 方法 var queryMatchingFiles = from file in files where file.Extension == ".html" let content = GetFileConetnt(file.FullName) where content.Contains(searchTerm) select file.FullName; //執(zhí)行查詢 Console.WriteLine("The term \"{0}\" was found in:", searchTerm); foreach (var filename in queryMatchingFiles) { Console.WriteLine(filename); } /// /// 讀取文件的所有內(nèi)容 /// /// /// static string GetFileConetnt(string fileName) { //如果我們?cè)诳煺蘸笠褎h除該文件,則忽略它,并返回空字符串。 return File.Exists(fileName) ? File.ReadAllText(fileName) : ""; }
到此這篇關(guān)于C#中LINQ to Objects的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
基于C#實(shí)現(xiàn)的多邊形沖突檢測(cè)實(shí)例
這篇文章主要給大家介紹了基于C#實(shí)現(xiàn)的多邊形沖突檢測(cè)的相關(guān)資料,文中介紹的方法并未使用第三方類庫(kù),可以完美解決這個(gè)問(wèn)題,需要的朋友可以參考下2021-07-07C#中l(wèi)abel內(nèi)容顯示不全、不完整的解決方法
這篇文章主要介紹了C#中l(wèi)abel內(nèi)容顯示不全、不完整的解決方法,只需要把兩個(gè)屬性設(shè)置一下即可解決這個(gè)問(wèn)題,需要的朋友可以參考下2015-06-06c#中SAPI使用總結(jié)——SpVoice的使用方法
最近使用C#重做了點(diǎn)名系統(tǒng)(要用到TTS,讓計(jì)算機(jī)點(diǎn)名)使用了SAPI,在這里總結(jié)一下SpVoice的使用方法。2011-10-10利用C#版OpenCV實(shí)現(xiàn)圓心求取實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于如何利用C#版OpenCV實(shí)現(xiàn)圓心求取的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05利用C#/VB.NET實(shí)現(xiàn)PPT轉(zhuǎn)換為HTML
利用PowerPoint可以很方便的呈現(xiàn)多媒體信息,且信息形式多媒體化,表現(xiàn)力強(qiáng)。但難免在某些情況下我們會(huì)需要將PowerPoint轉(zhuǎn)換為HTML格式,本文就為大家整理了轉(zhuǎn)換方法,希望對(duì)大家有所幫助2023-05-05