#c# #sourcegenerators #csharp-source-generator
Вопрос:
Я хочу создать статический класс, у которого должен быть метод, зависящий от других классов в конкретной ссылочной сборке.
упрощенный пример:
// Generator.csproj
[Generator]
public class MyGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
// Register a factory that can create our custom syntax receiver
context.RegisterForSyntaxNotifications(() => new MySyntaxReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
// var syntaxReceiver = (MySyntaxReceiver)context.SyntaxReceiver;
}
}
private class MySyntaxReceiver : ISyntaxReceiver
{
....
}
// Core.csproj
// namespace Core.Entities
class Entity1 : IAccessControl {}
class Entity2 {}
class Entity3 : IAccessControl {}
// Persistence.csproj => has a reference to Core project and the Generator
// this class should be generated ...
static class GeneratedClass
{
public static void DoSomethingEntity1()
public static void DoSomethingEntity3()
}
Я хочу найти Entity
классы в Core
проекте и создать класс в Persistence
проекте,
Проблема в том, что мой Core
проект недоступен, и он уже был скомпилирован ранее Persistence
. должен ли я использовать отражение или вручную прочитать основные объекты ? или есть лучший способ получить доступ к синтаксическому дереву в Core
проекте?
Ответ №1:
Поскольку Core
проект уже скомпилирован, мы не можем получить доступ к синтаксическому дереву, но мы можем пройти компиляцию, чтобы получить сборки, на которые имеются ссылки, затем просмотреть эти сборки и найти символы.
public void Execute(GeneratorExecutionContext context)
{
// finding Core reference assembly Symbols
IAssemblySymbol assemblySymbol =
context.Compilation.SourceModule.ReferencedAssemblySymbols.First(q => q.Name == "Core");
// use assembly symbol to get namespace and type symbols
// all members in namespace Core.Entities
var members = assemblySymbol.GlobalNamespace.
GetNamespaceMembers().First(q => q.Name == "Core")
.GetNamespaceMembers().First(q => q.Name == "Entities")
.GetTypeMembers().ToList();
var targets = new HashSet<INamedTypeSymbol>();
// find classes that implemented IAccessControl
foreach (var member in members.Where(m => m.AllInterfaces.Any(i => i.Name == "IAccessControl")))
{
targets.Add(member); // Entity1 Entity3
}
// generate source using targets ...
// context.AddSource("GeneratedClass", source);
}
надеюсь, этот пример поможет другим.