共用方式為


ImmutableArrays 的 Roslyn 分析器和程式碼感知程式庫

.NET 編譯器平台 (「Roslyn」) 可協助您建置程式碼感知程式庫。 程式碼感知程式庫提供您可以使用的功能,以及工具 (Roslyn 分析器) ,以協助您以最佳方式使用程式庫或避免錯誤。 本主題說明如何建置真實世界的 Roslyn 分析器,以在使用 System.Collections.Immutable NuGet 套件時攔截常見錯誤。 此範例也示範如何為分析器發現的程式碼問題提供程式碼修正。 使用者會在 Visual Studio 燈泡 UI 中看到程式碼修正,並可以自動套用程式碼修正。

開始

您需要下列專案來建置此範例:

  • Visual Studio 2015 (不是 Express Edition) 或更新版本。 您可以使用免費的 Visual Studio 社群版
  • Visual Studio SDK。 您也可以在安裝 Visual Studio 時,檢查 [常用工具] 底下的 [Visual Studio 擴充性工具] ,以同時安裝 SDK。 如果您已安裝 Visual Studio,您也可以移至主功能表 [ 檔案>新增>專案],在左側導覽窗格中選擇 [C# ],然後選擇 [ 擴充性]來安裝此 SDK。 當您選擇 [安裝 Visual Studio 擴充性工具] 階層連結專案範本時,它會提示您下載並安裝 SDK。
  • .NET 編譯器平台 (“Roslyn”) SDK。 您也可以移至主功能表 [ 檔案>新增>專案],在左側導覽窗格中選擇 [C# ],然後選擇 [ 擴充性]來安裝此 SDK。 當您選擇「下載 .NET 編譯器平台 SDK」階層連結專案範本時,它會提示您下載並安裝 SDK。 此 SDK 包含 Roslyn 語法視覺化工具。 這個有用的工具可協助您找出應該在分析器中尋找哪些程式碼模型類型。 分析器基礎結構會呼叫特定程式碼模型類型的程式碼,因此您的程式碼只會在必要時執行,而且只能專注於分析相關程式碼。

問題出在哪裡?

假設您提供具有 ImmutableArray (例如 System.Collections.Immutable.ImmutableArray<T>) 支援的程式庫。 C# 開發人員在 .NET 陣列方面擁有豐富的經驗。 不過,由於 ImmutableArrays 的性質和實作中使用的最佳化技術,C# 開發人員直覺會導致程式庫的使用者撰寫損壞的程式碼,如下所述。 此外,使用者在執行階段之前不會看到其錯誤,這不是他們在 Visual Studio with .NET 中習慣的品質體驗。

使用者熟悉編寫如下程式碼:

var a1 = new int[0];
Console.WriteLine("a1.Length = {0}", a1.Length);
var a2 = new int[] { 1, 2, 3, 4, 5 };
Console.WriteLine("a2.Length = {0}", a2.Length);

建立空陣列以填入後續程式碼行,以及使用集合初始化器語法,對於 C# 開發人員來說很熟悉。 不過,為 ImmutableArray 撰寫相同的程式碼會在執行階段當機:

var b1 = new ImmutableArray<int>();
Console.WriteLine("b1.Length = {0}", b1.Length);
var b2 = new ImmutableArray<int> { 1, 2, 3, 4, 5 };
Console.WriteLine("b2.Length = {0}", b2.Length);

第一個錯誤是由於 ImmutableArray 實作使用結構來包裝基礎資料儲存體。 結構必須具有無參數的建構函式,運算 default(T) 式才能傳回具有所有零或 Null 成員的結構。 當程式碼存取 b1.Length時,會發生執行階段 null 取消參考錯誤,因為 ImmutableArray 結構中沒有基礎儲存陣列。 建立空 ImmutableArray 的正確方式是 ImmutableArray<int>.Empty

集合初始化運算式的錯誤會發生,因為 ImmutableArray.Add 方法在每次呼叫時都會傳回新的實例。 因為 ImmutableArrays 從不改變,所以當您新增元素時,會返回一個新的 ImmutableArray 物件。此物件可能會因效能考量而與先前的 ImmutableArray 共享儲存空間。 因為b2在呼叫Add()五次之前指向第一個 ImmutableArray,所以b2是預設的 ImmutableArray。 呼叫 Length 也會當機,並顯示空指標解引用錯誤。 初始化 ImmutableArray 而不手動呼叫 Add 的正確方式是使用 ImmutableArray.CreateRange(new int[] {1, 2, 3, 4, 5})

尋找相關的語法節點類型來觸發分析器

若要開始建置分析器,請先找出您需要尋找的 SyntaxNode 類型。 從 檢視> 選項開啟 >,然後啟動 語法視覺化工具

請將編輯器的游標放在宣告b1的那一行。 您會看到「語法視覺化工具」顯示您位於語法樹狀結構的節點中 LocalDeclarationStatement 。 這個節點有一個 VariableDeclaration,而 又有一個 VariableDeclarator,而 EqualsValueClause又有一個 ,最後有一個 ObjectCreationExpression。 當您按一下「Syntax Visualizer」(語法視覺化工具)的樹狀結構中的節點時,編輯器視窗中的語法會高亮顯示,以顯示該節點所代表的程式碼。 SyntaxNode 子類型的名稱符合 C# 文法中使用的名稱。

建立分析器專案

從主功能表選擇 [檔案]> [新增]> [專案]。 在 [ 新增專案 ] 對話方塊的左側導覽列的 [C# 專案] 底下,選擇 [ 擴充性],然後在右窗格中選擇 [具有程式碼修正專案的分析器 ] 專案範本。 輸入名稱並確認對話方塊。

範本會開啟 DiagnosticAnalyzer.cs 檔案。 選擇編輯器緩衝區索引標籤。此檔案具有分析器類別(由您在專案中命名所形成),該類別是衍生自 DiagnosticAnalyzer(Roslyn API 類型)。 您的新類別會 DiagnosticAnalyzerAttribute 宣告您的分析器與 C# 語言相關,以便編譯器探索並載入您的分析器。

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class ImmutableArrayAnalyzer : DiagnosticAnalyzer
{}

您可以使用以 C# 程式碼為目標的 Visual Basic 實作分析器,反之亦然。 在 DiagnosticAnalyzerAttribute 中,選擇分析器是否以一種語言為目標或兩者都為目標,更為重要。 需要詳細建模語言的更複雜的分析器只能以單一語言為目標。 例如,如果您的分析器只檢查類型名稱或公用成員名稱,則可以使用 Roslyn 在 Visual Basic 和 C# 中提供的通用語言模型。 例如,FxCop 警告類別實作 ISerializable,但類別沒有與語言無關的 SerializableAttribute 屬性,且適用於 Visual Basic 和 C# 程式碼。

初始化分析器

在類別中 DiagnosticAnalyzer 向下捲動一點即可查看該 Initialize 方法。 編譯器會在啟動分析器時呼叫這個方法。 此方法會採用物件 AnalysisContext ,以便您的分析器取得上下文資訊,並為您想分析的程式碼類型註冊事件回調。

public override void Initialize(AnalysisContext context) {}

在此方法中開啟新行,然後輸入 “context.” 以查看 IntelliSense 完成清單。 您可以在完成清單中看到,有許多 Register... 方法可以處理各種類型的事件。 例如,第一個RegisterCodeBlockAction,回呼一個程式碼區塊,而這個區塊通常是在大括號之間的程式碼。 註冊區塊也會回調至您的代碼,以獲取字段的初始化器、屬性的賦值或可選參數的值。

另一個範例是, RegisterCompilationStartAction在編譯開始時回呼您的程式碼,當您需要收集多個位置的狀態時,這很有用。 例如,您可以建立資料結構來收集所有使用的符號,而且每次針對某些語法或符號回呼分析器時,您可以儲存資料結構中每個位置的相關資訊。 當您因編譯結束而被回呼時,您可以分析您儲存的所有位置,例如,報告程式碼從每個 using 陳述式中使用的符號。

使用 語法視覺化工具,您了解到希望在編譯器處理 ObjectCreationExpression 時被呼叫。 您可以使用此程式碼來設定回呼:

context.RegisterSyntaxNodeAction(c => AnalyzeObjectCreation(c),
                                 SyntaxKind.ObjectCreationExpression);

您可以註冊語法節點,並僅篩選物件建立語法節點。 按照慣例,分析器作者在註冊動作時使用 lambda,這有助於讓分析器保持無狀態。 您可以使用 Visual Studio 功能 [從使用方式產生] 來建立 AnalyzeObjectCreation 方法。 這會為您同樣生成正確類型的上下文參數。

設定分析器使用者的屬性

為了讓您的分析器適當地顯示在 Visual Studio UI 中,請尋找並修改下列程式碼行來識別您的分析器:

internal const string Category = "Naming";

"Naming" 變更為 "API Guidance"

接下來使用方案總管在專案中尋找並開啟Resources.resx檔案。 您可以輸入分析器、標題等的描述。您現在可以將所有這些值變更為 "Don't use ImmutableArray<T> constructor"。 您可以將字串格式參數放入字串中{0}( 、 {1}等),稍後當您呼叫 Diagnostic.Create()時,您可以提供 params 要傳遞的參數陣列。

分析物件建立運算式

AnalyzeObjectCreation 方法會採用程式碼分析器架構所提供的不同類型內容。 此Initialize 方法可讓您註冊AnalysisContext動作回呼,以設定您的分析器。 例如,SyntaxNodeAnalysisContext 有一個CancellationToken 可以讓你傳遞。 如果使用者開始在編輯器中輸入,Roslyn 會取消執行中的分析器,以節省工作並改善效能。 另一個範例是,此內容具有 Node 屬性,可傳回物件建立語法節點。

取得節點,您可以假設該節點是您篩選語法節點動作的類型:

var objectCreation = (ObjectCreationExpressionSyntax)context.Node;

第一次啟動時,使用分析器開啟 Visual Studio

藉由建置和執行分析器來啟動 Visual Studio (按 F5)。 因為 方案總管 中的啟動專案是 VSIX 專案,所以執行您的程式碼會建置程式碼和 VSIX,然後啟動安裝該 VSIX 的 Visual Studio。 zh-TW: 當您以這種方式啟動 Visual Studio 時,它會以不同的登錄區啟動,因此在建置分析器的過程中,測試執行個體不會影響您主要使用的 Visual Studio。 第一次以這種方式啟動時,Visual Studio 會執行數個初始化,類似於您在安裝 Visual Studio 之後第一次啟動 Visual Studio 時。

建立控制台專案,然後將陣列程式碼輸入到控制台應用程式 Main 方法中:

var b1 = new ImmutableArray<int>();
Console.WriteLine("b1.Length = {0}", b1.Length);
var b2 = new ImmutableArray<int> { 1, 2, 3, 4, 5 };
Console.WriteLine("b2.Length = {0}", b2.Length);

程式碼 ImmutableArray 行有波浪線,因為您必須取得不可變的 NuGet 套件,並將陳述式新增至 using 程式碼。 按 [方案總管 ] 中專案節點上的右邊指標按鈕,然後選擇 [管理 NuGet 套件]。 在 NuGet 管理員中,在搜尋方塊中輸入 [Immutable],然後在左窗格中選擇 System.Collections.Immutable 專案 (不要選擇 Microsoft.Bcl.Immutable),然後按右窗格中的 [安裝 ] 按鈕。 安裝套件會將參考新增到您的專案中。

您仍然會在 下ImmutableArray看到紅色波浪線,因此請將插入符號放在該 ID 中,然後按 Ctrl+ 鍵(句點) 調出建議的修正功能表,並選擇新增適當的using陳述式。

立即儲存全部並關閉當前的第二個 Visual Studio 實例,以便您保持在一個乾淨的狀態來繼續操作。

使用「編輯並繼續」功能完成分析器

在 Visual Studio 的第一個實例中,將插入符號放在AnalyzeObjectCreation方法的第一行,然後按F9來設定中斷點。

使用 F5 再次啟動分析器,然後在 Visual Studio 的第二個實例中,重新開啟您上次建立的主控台應用程式。

您會在中斷點返回 Visual Studio 的第一個實例,因為 Roslyn 編譯器看到物件建立運算式並呼叫分析器。

取得物件建立節點。objectCreation 跨過設定變數的行,然後在「立即視窗」中評估運算式 "objectCreation.ToString()"。 你看到變數指向的語法節點就是程式碼 "new ImmutableArray<int>()",正是你要找的。

取得 ImmutableArray<T> 型別物件。 您需要檢查正在建立的類型是否為 ImmutableArray。 首先,您會取得代表此類型的物件。 您可以使用語意模型檢查類型,以確保您擁有完全正確的類型,並且不會比較來自 ToString()的字串。 在函數結尾輸入以下程式碼行:

var immutableArrayOfTType =
    context.SemanticModel
           .Compilation
           .GetTypeByMetadataName("System.Collections.Immutable.ImmutableArray`1");

您可以在中繼資料中使用反引號 (') 和泛型參數數目來指定泛型類型。 這就是為什麼你看不到“......ImmutableArray<T>」。

語義模型上有許多有用的東西,可讓您詢問有關符號、資料流、變數存留期等的問題。Roslyn 出於各種工程原因(性能、建模錯誤代碼等)將語法節點與語義模型分開。 您想要編譯模型查閱參照中包含的資訊,以進行準確比較。

您可以拖曳編輯器視窗左側的黃色執行指標。 將它向上拖曳到設定 objectCreation 變數的行,然後使用 F10 逐步執行新程式碼行。 如果您將滑鼠指標停留在變數 immutableArrayOfType上,您會看到我們在語意模型中找到了確切的類型。

取得物件建構運算式的類型。 在本文中,「類型」有幾種用法,但這意味著如果您有「新 Foo」表達式,則需要取得 Foo 的模型。 需要取得物件建立運算式的類型,看看是否為ImmutableArray<T> 型別。 再次使用語意模型,以取得物件建立運算式中類型符號 (ImmutableArray) 的符號資訊。 在函數結尾輸入以下程式碼行:

var symbolInfo = context.SemanticModel.GetSymbolInfo(objectCreation.Type).Symbol as INamedTypeSymbol;

因為您的分析器需要處理編輯器緩衝區中不完整或不正確的程式碼 (例如,有遺 using 漏的陳述式),所以您應該檢查 symbolInfo 是否為 null。 您必須從符號資訊物件取得具名類型 (INamedTypeSymbol) 才能完成分析。

比較類型。 因為我們要尋找的是 T 的開放泛型類型,而且程式碼中的類型是具體的泛型類型,所以您可以查詢符號資訊以瞭解類型是由何所建構的 (開放泛型類型),並將該結果與 immutableArrayOfTType進行比較。 在方法結尾輸入下列內容:

if (symbolInfo != null &&
    symbolInfo.ConstructedFrom.Equals(immutableArrayOfTType))
{}

報告診斷。 報告診斷非常簡單。 您可以使用在專案範本中為您建立的規則,該規則是在 Initialize 方法之前定義的。 因為程式碼中的這種情況是錯誤,所以您可以將初始化 Rule 的行變更為 DiagnosticSeverity.Warning (紅色波浪線) 取代 DiagnosticSeverity.Error (綠色波浪線)。 規則的其餘部分會從您在操作指南開頭不遠處編輯的資源進行初始化。 您也需要報告曲線的位置,這是物件創建表達式的類型規格位置。 在區塊中 if 輸入此代碼:

context.ReportDiagnostic(Diagnostic.Create(Rule, objectCreation.Type.GetLocation()));

您的函數應該如下所示(可能格式不同):

private void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context)
{
    var objectCreation = (ObjectCreationExpressionSyntax)context.Node;
    var immutableArrayOfTType =
        context.SemanticModel
               .Compilation
               .GetTypeByMetadataName(
                   "System.Collections.Immutable.ImmutableArray`1");
    var symbolInfo = context.SemanticModel.GetSymbolInfo(objectCreation.Type).Symbol as
        INamedTypeSymbol;
    if (symbolInfo != null &&
        symbolInfo.ConstructedFrom.Equals(immutableArrayOfTType))
    {
        context.ReportDiagnostic(
            Diagnostic.Create(Rule, objectCreation.Type.GetLocation()));
    }
}

移除中斷點,以便您可以看到分析器的運作情況(並防止返回到第一個 Visual Studio 執行個體)。 將執行指標拖曳至方法的開頭,然後按 F5 繼續執行。 當您切換回 Visual Studio 的第二個實例時,編譯器會再次開始檢查程式碼,並呼叫您的分析器。 您可以看到在ImmutableType<int>下方有一個波浪線。

為程式碼問題新增「程式碼修正」

在開始之前,請關閉 Visual Studio 的第二個執行個體,並在您正在開發分析器的 Visual Studio 第一個執行個體中停止偵錯。

新增類別。 使用 [方案總管 ] 中專案節點上的快捷功能表 (右指標按鈕),然後選擇新增專案。 新增名為 的類別 BuildCodeFixProvider。 這個類別需要派生自 CodeFixProvider,而且你需要使用 Ctrl+. (句點)來呼叫新增正確 using 陳述式的程式碼修正。 這個類別也需要用屬性進行 ExportCodeFixProvider 註解,並且您需要添加一個 using 語句來解析 LanguageNames 枚舉。 您應該有一個包含以下代碼的類文件:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;

namespace ImmutableArrayAnalyzer
{
    [ExportCodeFixProvider(LanguageNames.CSharp)]
    class BuildCodeFixProvider : CodeFixProvider
    {}

存根化衍生成員。 現在,將編輯器的游標放置在識別碼CodeFixProvider中,然後按Ctrl+。(句點)以生成此抽象基類的框架。 這會為您產生一個屬性和一個方法。

實作屬性。 使用下列程式碼填入 FixableDiagnosticIds 屬性的 get 內文:

return ImmutableArray.Create(ImmutableArrayAnalyzer.DiagnosticId);

Roslyn 會比對這些識別碼 (這只是字串) 來整合診斷和修正。 專案範本會為您產生診斷識別碼,您可以隨意變更它。 屬性中的程式碼只會傳回分析器類別的識別碼。

RegisterCodeFixAsync 方法會接收一個 context 參數。 內容很重要,因為程式碼修正可以套用至多個診斷,或者在一行程式碼中可能有多個問題。 如果您在方法本文中輸入「context.」,IntelliSense 完成清單會顯示一些有用的成員。 您可以檢查 CancellationToken 成員,以確認是否有動作要取消這個修正。 有一個 Document 成員,其中包含許多有用的成員,可讓您存取專案和解決方案模型物件。 當您報告診斷時,指定的程式碼位置的開始和結尾由一個 Span 成員表示。

將方法設置為非同步。 您需要做的第一件事是將產生的方法宣告固定為方法 async 。 抽象類別實作的程式碼修正中省略了 async 關鍵字,即使該方法會傳回 Task

取得語法樹的根節點。 若要修改程式碼,您需要產生新的語法樹狀結構,其中包含程式碼修正所做的變更。 您需要從上下文中獲得 Document 才能調用 GetSyntaxRootAsync。 這是一個非同步方法,因為要取得語法樹存在未知的工作,可能包括從磁碟中取得檔案、解析檔案,以及建立該檔案的 Roslyn 程式碼模型。 Visual Studio UI 應該在這段期間內保持回應,是由 async 提供此功能的。 將方法中的程式碼行取代為下列內容:

var root = await context.Document
                        .GetSyntaxRootAsync(context.CancellationToken);

尋找有問題的節點。 您傳入上下文的範圍,但您找到的節點可能不是需要更改的程式碼。 報告的診斷只提供型別識別子的範圍(即波浪線所處的位置),但您需要取代整個物件建立表達式,包括開頭的 new 關鍵字和結尾的括號。 將下列程式碼新增至您的方法(並使用 Ctrl+. 來新增一個usingObjectCreationExpressionSyntax語句):

var objectCreation = root.FindNode(context.Span)
                         .FirstAncestorOrSelf<ObjectCreationExpressionSyntax>();

註冊燈泡用戶界面的程式碼修正。 當您註冊程式碼修正程式時,Roslyn 會自動插入 Visual Studio 燈泡 UI。 最終用戶將看到,當您的分析器用紅色波浪線標記錯誤的建構函數用法時,他們可以使用 Ctrl+(句點)。 因為您的程式碼修正提供者只會在發生問題時執行,所以您可以假設您有您要尋找的物件建立運算式。 從上下文參數中,您可以將以下代碼添加到方法末尾 RegisterCodeFixAsync 來註冊新的代碼修正:

context.RegisterCodeFix(
            CodeAction.Create("Use ImmutableArray<T>.Empty",
                              c => ChangeToImmutableArrayEmpty(objectCreation,
                                                               context.Document,
                                                               c)),
            context.Diagnostics[0]);

您需要將編輯器的插入符號放在標識符中,CodeAction然後使用 Ctrl+句點為此類型新增適當的using陳述式。

然後將編輯器的插入符號放在ChangeToImmutableArrayEmpty識別碼中,並再次使用Ctrl+.為您產生此方法存根。

您新增的最後一個程式碼片段會透過傳遞CodeAction和診斷 ID 來註冊發現的問題類型的修正。 在此範例中,只有一個診斷 ID,此程式碼提供的修正僅針對它,因此您只需傳入診斷 ID 陣列的第一個元素。 當您建立 CodeAction時,您會傳入燈泡 UI 應該用來做為程式碼修正說明的文字。 您也可以傳入一個函數,該函數會接受 CancellationToken 並傳回新的 Document。 新的文件有一個新的語法樹狀結構,其中包含呼叫 ImmutableArray.Empty的修補程式碼。 此程式碼片段使用 lambda,以便它可以關閉 objectCreation 節點和內容的 Document。

建構新的語法樹狀結構。 在您先前產生其存根的方法中 ChangeToImmutableArrayEmpty ,輸入程式碼行: ImmutableArray<int>.Empty;。 如果您再次檢視 「語法視覺化工具 」工具視窗,可以看到此語法是 SimpleMemberAccessExpression 節點。 這就是這個方法需要建構並在新文件中傳回的內容。

第一個對 ChangeToImmutableArrayEmpty 的變更是在 Task<Document> 之前加入 async ,因為程式碼產生器無法假設方法應為非同步。

使用下列程式碼填入內文,讓您的方法看起來類似下列內容:

private async Task<Document> ChangeToImmutableArrayEmpty(
    ObjectCreationExpressionSyntax objectCreation, Document document,
    CancellationToken c)
{
    var generator = SyntaxGenerator.GetGenerator(document);
    var memberAccess =
        generator.MemberAccessExpression(objectCreation.Type, "Empty");
    var oldRoot = await document.GetSyntaxRootAsync(c);
    var newRoot = oldRoot.ReplaceNode(objectCreation, memberAccess);
    return document.WithSyntaxRoot(newRoot);
}

您需要將編輯器的插入符放入SyntaxGenerator識別符中,並使用Ctrl+.句點來為此類型添加適當的using語句。

這段程式碼使用 SyntaxGenerator,這是建構新程式碼的有用類型。 取得有程式碼問題的文件的產生器後, ChangeToImmutableArrayEmpty 呼叫 MemberAccessExpression,傳遞具有我們要存取的成員的類型,並將成員的名稱作為字串傳遞。

接下來,方法會擷取檔的根目錄,而且因為這在一般情況下可能涉及任意工作,所以程式碼會等候此呼叫並傳遞取消權杖。 Roslyn 程式碼模型是不可變的,就像使用 .NET 字串一樣;當您更新字串時,您會收到一個新的字串物件作為回報。 當您呼叫 ReplaceNode時,您會傳回新的根節點。 大部分語法樹是共用的 (因為它是不可變的),但 objectCreation 節點會取代為 memberAccess 節點,以及所有父節點,直到語法樹根目錄。

試著修正程式碼

您現在可以按 F5 在 Visual Studio 的第二個實例中執行分析器。 開啟您先前使用的主控台專案。 現在,您應該會看到燈泡出現在新物件建立運算式所在 ImmutableArray<int>的位置。 如果您按 Ctrl+(句號),則您會看到程式碼修正提示,並且會在燈泡 UI 中看到自動產生的程式碼差異預覽。 Roslyn 為您創建了這個。

專業提示: 如果您啟動 Visual Studio 的第二個實例,卻沒有看到顯示出程式代碼修正的燈泡圖示,那麼您可能需要清除 Visual Studio 的元件快取。 清除快取會強制 Visual Studio 重新檢查元件,因此 Visual Studio 接著應該挑選最新的元件。 首先,關閉 Visual Studio 的第二個實例。 然後,在 Windows 檔案總管中,流覽至 %LOCALAPPDATA%\Microsoft\VisualStudio\16.0Roslyn\。 (“16.0” 會隨著 Visual Studio 的版本而變化。刪除子目錄 ComponentModelCache

討論視頻,完成程式碼項目

您可以在 此處查看所有完成的程式碼。 子資料夾 DoNotUseImmutableArrayCollectionInitializerDoNotUseImmutableArrayCtor 每個都有一個 C# 檔案來尋找問題,以及一個 C# 檔案,可實作 Visual Studio 燈泡 UI 中顯示的程式碼修正。 請注意,完成的程式碼具有更多的抽象性,以避免一遍又一遍地獲取 ImmutableArray<T> 類型物件。 它使用巢狀已註冊的操作,將類型物件儲存在執行分析物件建立和分析集合初始化的子動作時可用的上下文中。