Я пытаюсь создать инкрементальный генератор исходного кода, который генерирует конструкторы C# для внедрения зависимостей. Однако, похоже, мой генератор создает 2 источника с одинаковым именем Classes.g.cs.
Проект размещен здесь. Чтобы попробовать:
git clone https://github.com/MintPlayer/MintPlayer.Dotnet.Tools
Запустите Visual Studio, установите проект SourceGenerators (НЕ SourceGenerators.Debug) в качестве запускаемого проекта и нажмите F5. Если у вас установлен .NET Compiler Platform SDK с помощью установщика Visual Studio, генераторы будут запущены в файлах проекта отладки.
Вы вижу, что оператор точки останова, который я добавил в код, выполняется дважды, поэтому генератор создает этот файл один раз слишком часто.
Почему этот генератор запускается дважды?
Справочная информация
Классы XxxSourceGenerator являются настоящими генераторами. Они будут запускаться Visual Studio, пока вы вводите код.
[Generator(LanguageNames.CSharp)]
public class ClassNamesSourceGenerator : IIncrementalGenerator {
public void Initialize(IncrementalGeneratorInitializationContext context) {
var classDeclarationsProvider = context.SyntaxProvider
.CreateSyntaxProvider(
static (node, ct) => node is ClassDeclarationSyntax { } classDeclaration,
static (context, ct) => {
if (context.Node is ClassDeclarationSyntax classDeclaration &&
context.SemanticModel.GetDeclaredSymbol(classDeclaration, ct) is INamedTypeSymbol symbol) {
return new Models.ClassDeclaration { Name = symbol.Name };
} else {
return default;
}
}
)
.WithComparer(ValueComparers.ClassDeclarationValueComparer.Instance)
.Collect();
var fieldDeclarationsProvider = context.SyntaxProvider
.CreateSyntaxProvider(
static (node, ct) => node is FieldDeclarationSyntax { AttributeLists.Count: > 0 } fieldDeclaration
&& fieldDeclaration.Modifiers.Any(Microsoft.CodeAnalysis.CSharp.SyntaxKind.ReadOnlyKeyword),
static (context2, ct) => {
...
return new Models.FieldDeclaration {
Namespace = namespaceDeclaration.Name.ToString(),
FullyQualifiedClassName = classSymbol.ToDisplayString(),
ClassName = classSymbol.Name,
Name = symbol.Name,
FullyQualifiedTypeName = symbol.Type.ToDisplayString(),
Type = symbol.Type.Name,
};
}
)
.Collect();
Сначала они преобразуют данные от поставщиков и, в свою очередь, обращаются к нескольким производителям, которые индивидуально преобразуют символы в код C#.
var classNamesSourceProvider = classDeclarationsProvider
.Combine(config)
.Select(static (p, ct) => new Producers.ClassNamesProducer(declarations: p.Left, rootNamespace: p.Right.RootNamespace!));
var classNameListSourceProvider = classDeclarationsProvider
.Combine(config)
.Select(static (p, ct) => new Producers.ClassNameListProducer(declarations: p.Left, rootNamespace: p.Right.RootNamespace!));
var fieldDeclarationSourceProvider = fieldDeclarationsProvider
.Combine(config)
.Select(static (p, ct) => new Producers.FieldNameListProducer(declarations: p.Left, rootNamespace: p.Right.RootNamespace!));
Затем вам нужно объединить выходные данные всех этих производителей и передать поставщика исходного кода в .NET/VS
// Combine all Source Providers
var sourceProvider = classNamesSourceProvider
.Combine(classNameListSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right })
.Combine(fieldDeclarationSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right });
// Generate Code
context.RegisterSourceOutput(sourceProvider, static (c, g) => g?.Produce(c));
Изменить
Примечательно, что вместо этого я использую этот фрагмент:
var sourceProvider = fieldDeclarationSourceProvider
.Combine(classNamesSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right })
.Combine(classNameListSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right });
файл fieldDeclarations генерируется только один раз, но файл classNameList создается дважды, поэтому, очевидно, нижний поставщик запускается дважды
// Generates ClassNameList.g.cs twice
var sourceProvider = classNamesSourceProvider
.Combine(fieldDeclarationSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right })
.Combine(classNameListSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right });
// Generates FieldNameList.g.cs twice
var sourceProvider = classNamesSourceProvider
.Combine(classNameListSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right })
.Combine(fieldDeclarationSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right });
// Generates ClassNameList.g.cs twice
var sourceProvider = fieldDeclarationSourceProvider
.Combine(classNamesSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right })
.Combine(classNameListSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right });
// Generates ClassNames.g.cs twice
var sourceProvider = fieldDeclarationSourceProvider
.Combine(classNameListSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right })
.Combine(classNamesSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right });
// Generates ClassNames.g.cs twice
var sourceProvider = classNameListSourceProvider
.Combine(fieldDeclarationSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right })
.Combine(classNamesSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right });
// Generates FieldNameList.g.cs twice
var sourceProvider = classNameListSourceProvider
.Combine(classNamesSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right })
.Combine(fieldDeclarationSourceProvider)
.SelectMany(static (p, _) => new Producer[] { p.Left, p.Right });
Подробнее здесь: https://stackoverflow.com/questions/790 ... e-filename
Инкрементный генератор создает дубликаты имен файлов ⇐ C#
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение