Анализаторы Roslyn и библиотека с поддержкой кода для неизменяемыхArrays
Платформа компилятора .NET (Roslyn) помогает создавать библиотеки с поддержкой кода. Библиотека с поддержкой кода предоставляет функциональные возможности, которые можно использовать и использовать (анализаторы Roslyn), чтобы лучше использовать библиотеку или избежать ошибок. В этом разделе показано, как создать реальный анализатор Roslyn для перехвата распространенных ошибок при использовании пакета NuGet System.Collections.Immutable . В примере также показано, как предоставить исправление кода для проблемы с кодом, обнаруженной анализатором. Пользователи видят исправления кода в пользовательском интерфейсе лампочки Visual Studio и могут автоматически применять исправление для кода.
Начать
Для создания этого примера вам потребуется следующее:
- Visual Studio 2015 (а не Express Edition) или более поздней версии. Вы можете использовать бесплатную версию Visual Studio Community Edition
- Visual Studio SDK. Кроме того, при установке Visual Studio проверка средства расширяемости Visual Studio в разделе Common Tools для установки пакета SDK одновременно. Если вы уже установили Visual Studio, вы также можете установить этот пакет SDK, перейдя в главное меню "Файл>нового>проекта", выбрав C# в левой области навигации и выбрав расширяемость. При выборе шаблона проекта "Установка средств расширяемости Visual Studio" появится запрос на скачивание и установку пакета SDK.
- Пакет SDK для платформы компилятора .NET (Roslyn). Вы также можете установить этот пакет SDK, перейдя в главное меню "Файл>нового>проекта", выбрав C# в области навигации слева и выбрав расширяемость. При нажатии кнопки "Скачать шаблон проекта платформы компилятора .NET" будет предложено скачать и установить пакет SDK. Этот пакет SDK включает визуализатор синтаксиса Roslyn. Это полезное средство помогает определить, какие типы моделей кода следует искать в анализаторе. Инфраструктура анализатора вызывает код для определенных типов модели кода, поэтому код выполняется только при необходимости и может сосредоточиться только на анализе соответствующего кода.
В чем может быть проблема?
Представьте, что вы предоставляете библиотеку с поддержкой ImmutableArray (например, System.Collections.Immutable.ImmutableArray<T>). Разработчики C# имеют широкий опыт работы с массивами .NET. Однако из-за характера неизменяемыхArrays и методов оптимизации, используемых в реализации, интуиции разработчика C# приводят к тому, что пользователи библиотеки могут писать неисправный код, как описано ниже. Кроме того, пользователи не видят свои ошибки до времени выполнения, что не является качеством, который они используются в Visual Studio с .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#. Однако написание того же кода для неизменяемогоArray завершает работу во время выполнения:
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 нет базового массива хранилища. Правильный способ создать пустой неизменяемыйArray ImmutableArray<int>.Empty
.
Ошибка с инициализаторами коллекции происходит, так как ImmutableArray.Add
метод возвращает новые экземпляры при каждом вызове. Так как неизменяемыеArrays никогда не изменяются, при добавлении нового элемента вы вернетесь к новому объекту ImmutableArray (который может предоставлять общий доступ к хранилищу по причинам производительности с ранее существующим ImmutableArray). Так как b2
указывает на первый неизменяемыйArray перед вызовом Add()
пять раз, b2
это неизменяемыйArray по умолчанию. Длина вызова в ней также завершается с ошибкой расшифровки null. Правильный способ инициализации неизменяемогоArray без вызова add вручную — использовать ImmutableArray.CreateRange(new int[] {1, 2, 3, 4, 5})
.
Поиск соответствующих типов синтаксического узла для активации анализатора
Чтобы начать сборку анализатора, сначала выясните, какой тип СинтаксисNode необходимо искать. Запустите визуализатор синтаксиса из меню "Другие>визуализатор синтаксиса Windows>Roslyn".
Поместите курсор редактора в строку, которая объявляет b1
. Вы увидите, что визуализатор синтаксиса отображается в LocalDeclarationStatement
узле дерева синтаксиса. Этот узел имеет , который, в свою очередь, имеет VariableDeclaration
VariableDeclarator
, который, в свою очередь, имеет EqualsValueClause
и, наконец, есть ObjectCreationExpression
. Щелкнув дерево визуализатора синтаксиса узлов, синтаксис в окне редактора выделяется, чтобы отобразить код, представленный этим узлом. Имена подтипов SyntaxNode соответствуют именам, используемым в грамматике C#.
Создание проекта анализатора
В главном меню выберите "Файл>нового>проекта". В диалоговом окне "Новый проект" в проектах C# в левой панели навигации выберите расширяемость и в правой области выберите анализатор с шаблоном проекта "Исправление кода". Введите имя и подтвердите диалоговое окно.
Шаблон открывает файл DiagnosticAnalyzer.cs . Выберите вкладку буфера редактора. Этот файл имеет класс анализатора (сформированный из имени, которое вы дали проекту), который является производным от DiagnosticAnalyzer
(типа API Roslyn). Новый класс имеет DiagnosticAnalyzerAttribute
объявление, что анализатор относится к языку C#, чтобы компилятор обнаружил и загружает анализатор.
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class ImmutableArrayAnalyzer : DiagnosticAnalyzer
{}
Анализатор можно реализовать с помощью Visual Basic, предназначенный для кода C#, и наоборот. Более важно в 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);
Регистрируется для узла синтаксиса и фильтруется только для узлов синтаксиса создания объектов. По соглашению авторы анализаторов используют лямбда-код при регистрации действий, что помогает обеспечить без отслеживания состояния анализаторов. Для создания AnalyzeObjectCreation
метода можно использовать функцию Создания из использования Visual Studio. Это также создает правильный тип параметра контекста.
Задание свойств для пользователей анализатора
Чтобы анализатор отображались в пользовательском интерфейсе Visual Studio соответствующим образом, найдите и измените следующую строку кода, чтобы определить анализатор:
internal const string Category = "Naming";
Измените "Naming"
на "API Guidance"
.
Затем найдите и откройте файл Resources.resx в проекте с помощью Обозреватель решений. Вы можете поместить описание анализатора, заголовка и т. д. Вы можете изменить значение для всех этих "Don't use ImmutableArray<T> constructor"
значений. Аргументы форматирования строк можно поместить в строку ({0}, {1}и т. д.), а затем при вызове Diagnostic.Create()
можно указать params
массив аргументов, передаваемых.
Анализ выражения создания объекта
Метод AnalyzeObjectCreation
принимает другой тип контекста, предоставляемый платформой анализатора кода. AnalysisContext
Метод Initialize
позволяет зарегистрировать обратные вызовы действий для настройки анализатора. Например, естьSyntaxNodeAnalysisContext
CancellationToken
, что можно обойти. Если пользователь начинает вводить в редакторе, Roslyn отменит выполнение анализаторов, чтобы сохранить работу и повысить производительность. В качестве другого примера этот контекст имеет свойство Node, которое возвращает узел синтаксиса создания объекта.
Получите узел, который можно предположить, является типом, для которого отфильтровано действие синтаксического узла:
var objectCreation = (ObjectCreationExpressionSyntax)context.Node;
Запуск Visual Studio с помощью анализатора в первый раз
Запустите Visual Studio, создав и выполнив анализатор (нажмите клавишу F5). Так как запускаемый проект в Обозреватель решений является проектом VSIX, запуск кода создает код и VSIX, а затем запускает Visual Studio с установленным VSIX. При запуске 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 введите "Неизменяемый" в поле поиска и выберите элемент System.Collections.Immutable (не выбирайте Microsoft.Bcl.Immutable) в левой области и нажмите кнопку "Установить " в правой области. Установка пакета добавляет ссылку на ссылки на проект.
Вы по-прежнему видите красные волнистые фигурыImmutableArray
, поэтому поместите курсор в этот идентификатор и нажмите клавиши CTRL+. (период), чтобы открыть предлагаемое меню исправления и выбрать, чтобы добавить соответствующую using
инструкцию.
Сохраните все и закройте второй экземпляр Visual Studio, чтобы поместить вас в чистое состояние, чтобы продолжить.
Завершение анализатора с помощью редактирования и продолжения
В первом экземпляре Visual Studio задайте точку останова AnalyzeObjectCreation
в начале метода, нажав клавишу F9 с помощью курсора на первой строке.
Запустите анализатор снова с помощью F5, а во втором экземпляре Visual Studio снова откройте консольное приложение, созданное в последний раз.
Вы вернеесь к первому экземпляру Visual Studio в точке останова, так как компилятор Roslyn увидел выражение создания объекта и вызвал в анализатор.
Получите узел создания объекта. Выполните шаг по строке, которая задает objectCreation
переменную, нажав клавишу F10, и в окне интерпретации вычисляется выражение "objectCreation.ToString()"
. Вы видите, что синтаксический узел, на который указывает переменная, — это код "new ImmutableArray<int>()"
, который вы ищете.
Получение объекта ImmutableArray<T> Type. Если созданный тип является неизменяемымArray, необходимо проверка. Сначала вы получите объект, представляющий этот тип. Вы проверка типы с помощью семантической модели, чтобы убедиться, что у вас есть правильный тип, и вы не сравниваете строку изToString()
. Введите следующую строку кода в конце функции:
var immutableArrayOfTType =
context.SemanticModel
.Compilation
.GetTypeByMetadataName("System.Collections.Immutable.ImmutableArray`1");
Вы назначаете универсальные типы в метаданных с обратными знаками (') и числом универсальных параметров. Именно поэтому вы не видите "... НеизменяемыйArray<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. Так как эта ситуация в коде является ошибкой, можно изменить строку, которая инициализировала правило для замены 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+(period).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". В тексте метода будет отображаться список завершения IntelliSense. Есть член CancelToken, который вы можете проверка, чтобы узнать, хотите ли что-то отменить исправление. Существует элемент Document с большим количеством полезных элементов и позволяет получить доступ к объектам модели проекта и решения. Существует элемент Span, который является началом и концом расположения кода, указанного при сообщении о диагностике.
Сделайте метод асинхронным. Первое, что необходимо сделать, — исправить созданное объявление метода, чтобы быть методом async
. Исправление кода для отрезания реализации абстрактного класса не включает async
ключевое слово даже если метод возвращает значениеTask
.
Получите корень дерева синтаксиса. Чтобы изменить код, необходимо создать новое дерево синтаксиса с изменениями исправления кода. Для вызова GetSyntaxRootAsync
требуется Document
из контекста. Это асинхронный метод, так как для получения дерева синтаксиса неизвестно, возможно, в том числе получение файла с диска, анализ его и создание модели кода Roslyn для него. Пользовательский интерфейс Visual Studio должен реагировать в течение этого времени, что позволяет использовать async
его. Замените строку кода в методе следующим образом:
var root = await context.Document
.GetSyntaxRootAsync(context.CancellationToken);
Найдите узел с проблемой. Вы передаете диапазон контекста, но узел, который вы нашли, может не быть кодом, который необходимо изменить. Сообщаемая диагностика предоставила только диапазон для идентификатора типа (где принадлежала волнистая черта), но необходимо заменить все выражение создания объекта, включая new
ключевое слово в начале и скобки в конце. Добавьте следующий код в метод (и используйте ctrl+. для добавления инструкции using
для ObjectCreationExpressionSyntax
):
var objectCreation = root.FindNode(context.Span)
.FirstAncestorOrSelf<ObjectCreationExpressionSyntax>();
Зарегистрируйте исправление кода для пользовательского интерфейса лампочки. При регистрации исправления кода Roslyn автоматически подключается к пользовательскому интерфейсу лампочки Visual Studio. Конечные пользователи увидят, что они могут использовать клавиши CTRL+ (период), когда анализатор щелкает неправильный ImmutableArray<T>
конструктор. Так как поставщик исправлений кода выполняется только при возникновении проблемы, можно предположить, что у вас есть нужное выражение создания объекта. В параметре контекста можно зарегистрировать новое исправление кода, добавив следующий код в конец RegisterCodeFixAsync
метода:
context.RegisterCodeFix(
CodeAction.Create("Use ImmutableArray<T>.Empty",
c => ChangeToImmutableArrayEmpty(objectCreation,
context.Document,
c)),
context.Diagnostics[0]);
Необходимо поместить курсор редактора в идентификатор, CodeAction
а затем с помощью ctrl+ (period) добавить соответствующую using
инструкцию для этого типа.
Затем поместите курсор редактора в ChangeToImmutableArrayEmpty
идентификатор и нажмите клавиши CTRL+. Чтобы создать заглушку этого метода.
Этот последний фрагмент кода, который вы добавили, регистрирует исправление кода путем передачи CodeAction
идентификатора диагностики для типа обнаруженной проблемы. В этом примере существует только один идентификатор диагностики, для который этот код предоставляет исправления, поэтому можно просто передать первый элемент массива идентификаторов диагностики. При создании CodeAction
кода вы передаете текст, который пользовательский интерфейс лампочки должен использовать в качестве описания исправления кода. Вы также передаете функцию, которая принимает отменуToken и возвращает новый документ. В новом документе есть новое дерево синтаксиса, включающее исправленный код, который вызывает ImmutableArray.Empty
. Этот фрагмент кода использует лямбда-код, чтобы он смог закрыть через узел objectCreation и документ контекста.
Создайте новое дерево синтаксиса. В методеChangeToImmutableArrayEmpty
, заглушки которого вы создали ранее, введите строку кода: ImmutableArray<int>.Empty;
Если снова просмотреть окно средства визуализатора синтаксиса, вы увидите, что этот синтаксис является узлом SimpleMemberAccessExpression. Это то, что этот метод должен создавать и возвращать в новом документе.
Первое изменение ChangeToImmutableArrayEmpty
— добавить async
раньше Task<Document>
, так как генераторы кода не могут предположить, что метод должен быть асинхронным.
Заполните текст следующим кодом, чтобы метод выглядел следующим образом:
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
который является полезным типом для создания нового кода. После получения генератора для документа, имеющего проблему с кодом, вызываетсяMemberAccessExpression
, ChangeToImmutableArrayEmpty
передав тип, имеющий член, к которому мы хотим получить доступ, и передать имя члена в виде строки.
Затем метод извлекает корень документа, и так как это может включать произвольные действия в общем случае, код ожидает этот вызов и передает маркер отмены. Модели кода Roslyn неизменяемы, например работа со строкой .NET; При обновлении строки возвращается новый объект строки. При вызове ReplaceNode
вы получите новый корневой узел. Большая часть дерева синтаксиса является общим (так как она неизменяема), но objectCreation
узел заменяется memberAccess
на узел, а также все родительские узлы до корневого дерева синтаксиса.
Попробуйте исправить код
Теперь можно нажать клавишу F5 , чтобы выполнить анализатор во втором экземпляре Visual Studio. Откройте проект консоли, который вы использовали раньше. Теперь должна появиться лампочка, в которой находится ImmutableArray<int>
новое выражение создания объекта. Если нажать клавиши CTRL+ (период), вы увидите исправление кода, и в пользовательском интерфейсе лампочки появится автоматически сформированная разница в коде. Рослин создает это для вас.
Совет про. Если запустить второй экземпляр Visual Studio, и вы не видите лампочки с исправлением кода, может потребоваться очистить кэш компонентов Visual Studio. Очистка кэша заставляет Visual Studio повторно проверять компоненты, поэтому Visual Studio должен затем забрать последний компонент. Во-первых, завершите работу второго экземпляра Visual Studio. Затем в Windows Обозреватель перейдите в папку %LOCALAPPDATA%\Microsoft\VisualStudio\16.0Roslyn\. (Изменение версии 16.0 с версии на версию с помощью Visual Studio.) Удалите подкаталог ComponentModelCache.
Видео и проект готового кода
Здесь можно просмотреть весь готовый код. Вложенные папки DoNotUseImmutableArrayCollectionInitializer и DoNotUseImmutableArrayCtor имеют файл C# для поиска проблем и файла C#, реализующего исправления кода, которые отображаются в пользовательском интерфейсе лампочки Visual Studio. Обратите внимание, что готовый код имеет немного больше абстракции, чтобы избежать получения объекта типа ImmutableArray<T> . Он использует вложенные зарегистрированные действия для сохранения объекта типа в контексте, который доступен при выполнении вложенных действий (анализ создания объектов и анализа инициализаций коллекции).