溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#中的LINQ?to?Objects實例分析

發(fā)布時間:2022-06-06 15:03:13 來源:億速云 閱讀:221 作者:iii 欄目:開發(fā)技術

這篇文章主要介紹了C#中的LINQ to Objects實例分析的相關知識,內(nèi)容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇C#中的LINQ to Objects實例分析文章都會有所收獲,下面我們一起來看看吧。

Linq和反射

.NET Framework 類庫反射 API 可用于檢查 .NET 程序集中的元數(shù)據(jù),以及創(chuàng)建位于該程序集中的類型、類型成員、參數(shù)等等的集合。 因為這些集合支持泛型 IEnumerable 接口,所以可以使用 LINQ 查詢它們。

下面的示例演示了如何將 LINQ 與反射配合使用以檢索有關與指定搜索條件匹配的方法的特定元數(shù)據(jù)。 在這種情況下,該查詢將在返回數(shù)組等可枚舉類型的程序集中查找所有方法的名稱。

該示例使用 GetTypes 方法返回指定程序集中的類型的數(shù)組。 將應用 where 篩選器,以便僅返回公共類型。 對于每個公共類型,子查詢使用從 GetMethods 調(diào)用返回的 MethodInfo 數(shù)組生成。 篩選這些結(jié)果,以僅返回其返回類型為數(shù)組或?qū)崿F(xiàn) IEnumerable 的其他類型的方法。 最后,通過使用類型名稱作為鍵來對這些結(jié)果進行分組。

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)操作實質(zhì)上是查詢,因此非常適合使用 LINQ 方法。

本部分中的查詢是非破壞性查詢。 它們不用于更改原始文件或文件夾的內(nèi)容。 這遵循了查詢不應引起任何副作用這條規(guī)則。 通常,修改源數(shù)據(jù)的任何代碼(包括執(zhí)行創(chuàng)建/更新/刪除運算符的查詢)應與只查詢數(shù)據(jù)的代碼分開。

實例1、如何查詢具有指定屬性或名稱的文件

此示例演示如何查找指定目錄樹中具有指定文件擴展名(例如“.txt”)的所有文件,還演示如何根據(jù)創(chuàng)建時間返回樹中最新或最舊的文件。

//該查詢將所有生產(chǎn)的完整路徑。txt文件指定的文件夾包括子文件夾下。
const string path = @"C:\Program Files (x86)\Microsoft Visual Studio 14.0\";
//取文件系統(tǒng)快照
var dir = new DirectoryInfo(path);
//該方法假定應用程序在指定路徑下的所有文件夾都具有搜索權(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í)行一個新的查詢,通過查詢舊文件的創(chuàng)建時間作為一個出發(fā)點
//Last:選最后一個,因為是按日期升序,所以最新的是指最后一個
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}");

C#中的LINQ?to?Objects實例分析

實例2、如何按照擴展名對文件進行分組

此示例演示如何使用 LINQ 對文件或文件夾列表執(zhí)行高級分組和排序操作。此外,它還演示如何使用 Skip 和 Take 方法對控制臺窗口中的輸出進行分頁。

下面的查詢演示如何按文件擴展名對指定目錄樹的內(nèi)容進行分組。

const string path = @"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7";
//“path”的長度,后續(xù)用于在輸出時去掉“path”這段前綴
var trimLength = path.Length;
//取文件系統(tǒng)快照
var dir = new DirectoryInfo(path);
//該方法假定應用程序在指定路徑下的所有文件夾都具有搜索權(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ù),則分頁輸出。 
PageOutput(trimLength, query);

private static void PageOutput(int rootLength, IOrderedEnumerable<string, FileInfo>> query)
{
    //跳出分頁循環(huán)的標志
    var isAgain = true;
    //控制臺輸出的高度
    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”開始顯示“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("點擊“任意鍵”繼續(xù),按“End”鍵退出");

            //給用戶選擇是否跳出
            var key = Console.ReadKey().Key;
            if (key != ConsoleKey.End) continue;

            isAgain = false;
            break;
        } while (currentLine < g.Count());

        if (!isAgain)
        {
            break;
        }
    }
}

C#中的LINQ?to?Objects實例分析

為了使您可以查看所有結(jié)果,此示例還演示如何按頁查看結(jié)果。這些方法可應用于 Windows 和 Web 應用程序。

請注意,由于代碼將對組中的項進行分頁,因此需要嵌套的 foreach 循環(huán)。此外,還會使用某他某個邏輯來計算列表中的當前位置,以及使用戶可以停止分頁并退出程序。在這種特定情況下,將針對原始查詢的緩存結(jié)果運行分頁查詢。

實例3、如何查詢一組文件夾中的總字節(jié)數(shù)

此示例演示如何檢索指定文件夾及其所有子文件夾中的所有文件所使用的總字節(jié)數(shù)。

Sum 方法添加在 select 子句中選擇的所有項的值。您可以輕松修改此查詢以檢索指定目錄樹中的最大或最小文件,方法是調(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é)果,以避免多次訪問文件系統(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);

C#中的LINQ?to?Objects實例分析

如果您只需要統(tǒng)計特定目錄樹中的字節(jié)數(shù),則可以更高效地實現(xiàn)此目的,而無需創(chuàng)建 LINQ 查詢,因為該查詢會引發(fā)創(chuàng)建列表集合作為數(shù)據(jù)源的系統(tǒng)開銷。隨著查詢復雜度的增加,或者當您必須對同一數(shù)據(jù)源運行多個查詢時,LINQ 方法的有用性也會隨之增加。

實例4、如何比較兩個文件夾中的內(nèi)容

此示例演示比較兩個文件列表的三種方法:

  • (1)查詢一個指定兩個文件列表是否相同的布爾值;

  • (2)查詢用于檢索同時位于兩個文件夾中的文件的交集;

  • (3)查詢用于檢索位于一個文件夾中但不在另一個文件夾中的文件的差集;

//創(chuàng)建兩個帶比較的文件夾
const string path2 = @"E:\Test1";
const string path3 = @"E:\Test2";

var dir1 = new DirectoryInfo(path2);
var dir2 = new DirectoryInfo(path3);

//取文件快照
var files1 = dir1.GetFiles("*.*", SearchOption.AllDirectories);
var files2 = dir2.GetFiles("*.*", SearchOption.AllDirectories);

//自定義文件比較器
var comparer = new FileComparer();

//該查詢確定兩個文件夾包含相同的文件列表,基于自定義文件比較器。查詢立即執(zhí)行,因為它返回一個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.");
}

//差集:對比兩個文件夾的差異
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);
}

//該實現(xiàn)定義了一個非常簡單的兩個 FileInfo 對象之間的比較。它只比較文件的名稱和它們字節(jié)數(shù)的長度
public class FileComparer : IEqualityComparer
{
    public bool Equals(FileInfo x, FileInfo y)
    {
        return string.Equals(x.Name, y.Name, StringComparison.CurrentCultureIgnoreCase) && x.Length == y.Length;
    }

    //返回一個比較標準的哈希值。根據(jù) IEqualityComparer 規(guī)則,如果相等,那么哈希值也必須是相等的。
    //因為這里所定義的相等只是一個簡單的值相等,而不是引用標識,所以兩個或多個對象將產(chǎn)生相同的哈希值是可能的。 
    public int GetHashCode(FileInfo obj)
    {
        var s = string.Format("{0}{1}", obj.Name, obj.Length);

        return s.GetHashCode();
    }
}

C#中的LINQ?to?Objects實例分析

【注意】 可以修改上述這些方法以便對任意類型的對象序列進行比較。

此處顯示的 FileComparer 類演示如何將自定義比較器類與標準查詢運算符一起使用。該類不是為在實際方案中使用而設計的。它只是使用每個文件的名稱和長度(以字節(jié)為單位)來確定每個文件夾的內(nèi)容是否相同。在實際方案中,應對此比較器進行修改以執(zhí)行更嚴格的相等性檢查。

實例5、如何在目錄樹中查詢最大的文件

此示例演示與文件大?。ㄒ宰止?jié)為單位)相關的五種查詢:

  • 如何檢索最大文件的大?。ㄒ宰止?jié)為單位);

  • 如何檢索最小文件的大?。ㄒ宰止?jié)為單位);

  • 如何從指定的根文件夾下的一個或多個文件夾檢索 FileInfo 對象最大或最小文件;

  • 如何檢索一個序列,如 10 個最大文件。

下面的示例包含五種不同的查詢,這些查詢演示如何根據(jù)文件大?。ㄒ宰止?jié)為單位)查詢和分組文件??梢暂p松地修改這些示例,以使查詢基于 FileInfo對象的某個其他屬性。

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();
//倒序排列的第一個就是最大的文件
var longestFile = fileInfos.First();
//倒序排列的第一個就是最小的文件
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個最大的文件
var queryTenLargest = fileInfos.Take(10);
foreach (var v in queryTenLargest)
{
    Console.WriteLine("{0}: {1} bytes", v.FullName, v.Length);
}

C#中的LINQ?to?Objects實例分析

若要返回一個或多個完整的 FileInfo 對象,查詢必須首先檢查數(shù)據(jù)源中的每個對象,然后按這些對象的 Length 屬性的值排序它們。然后查詢可以返回具有最大長度的單個對象或序列。使用 First 可返回列表中的第一個元素。使用 Take 可返回前 n 個元素。指定降序排序順序可將最小的元素放在列表的開頭。

實例6、如何在目錄樹中查詢重復的文件

有時,多個文件夾中可能存在同名的文件。例如,在 Visual Studio 安裝文件夾中,有多個文件夾包含 readme.htm 文件。

此示例演示如何在指定的根文件夾中查詢這樣的重復文件名。

第二個示例演示如何查詢其大小和創(chuàng)建時間也匹配的文件。

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);
    //路徑的長度
    var charsToSkip = path.Length;

    //注意一個復合鍵的使用。三個屬性都匹配的文件屬于同一組。
    //匿名類型也可以用于復合鍵,但不能跨越方法邊界。 
    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();

    //分頁輸出
    PageOutputstring>(queryDupNames);

}

private static void PageOutput(IEnumerable> queryDupNames)
{
    //跳出分頁循環(huán)的標志 
    var isAgain = true;
    var numLines = Console.WindowHeight - 3;

    var dupNames = queryDupNames as IGrouping[] ?? queryDupNames.ToArray();
    foreach (var queryDupName in dupNames)
    {
        //分頁開始
        var currentLine = 0;

        do
        {
            Console.Clear();
            Console.WriteLine("Filename = {0}", queryDupName.Key.ToString() == string.Empty ? "[none]" : queryDupName.Key.ToString());

            //跳過 currentLine 行,取 numLines 行
            var resultPage = queryDupName.Skip(currentLine).Take(numLines);

            foreach (var fileName in resultPage)
            {
                Console.WriteLine("\t{0}", fileName);
            }

            //增量器記錄已顯示的行數(shù)
            currentLine += numLines;

            //讓用戶自動選擇下一下
            //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;
            //}

            //按得有點累,還是讓它自動下一頁吧
            Thread.Sleep(100);

        } while (currentLine < queryDupName.Count());

        //if (!isAgain)
        //    break;
    }
}

C#中的LINQ?to?Objects實例分析

第一個查詢使用一個簡單的鍵確定是否匹配;這會找到同名但內(nèi)容可能不同的文件。第二個查詢使用復合鍵并根據(jù) FileInfo 對象的三個屬性來確定是否匹配。此查詢非常類似于查找同名且內(nèi)容類似或相同的文件。

實例7、如何在文件夾中查詢文件的內(nèi)容

此示例演示如何查詢指定目錄樹中的所有文件、打開每個文件并檢查其內(nèi)容。 此類技術可用于對目錄樹的內(nèi)容創(chuàng)建索引或反向索引。 此示例中執(zhí)行的是簡單的字符串搜索。 但是,可使用正則表達式執(zhí)行更復雜類型的模式匹配。

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";
//搜索每個文件的內(nèi)容。
//您也可以使用正則表達式替換 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)
{
    //如果我們在快照后已刪除該文件,則忽略它,并返回空字符串。 
    return File.Exists(fileName) ? File.ReadAllText(fileName) : "";
}

C#中的LINQ?to?Objects實例分析

關于“C#中的LINQ to Objects實例分析”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“C#中的LINQ to Objects實例分析”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI