【问题标题】:How to access project referenced assemblies in source generator?如何在源生成器中访问项目引用的程序集?
【发布时间】:2021-08-10 18:40:59
【问题描述】:

我有一个类库项目 First.csproj,其中包含一个文件 ICar.cs:

namespace First
{
    public interface ICar
    {
        string Name { get; set; }
    }
}

我有一个空的类库项目 Second.csproj 和 Analyzer(源生成器)项目 Second.Generator.csproj:

  1. First.csproj - 没有项目引用
  2. Second.csproj - 引用了 First.csproj 和 Second.Generator.csproj
  3. Second.Generator.csproj - 没有项目引用

我想编写 Second.Generator.csproj MySourceGenerator.cs,它采用 Second.csproj,搜索其所有类库项目引用(在本例中为 First.csproj)并实现其所有接口。结果应该是这个生成的代码:

namespace Second
{
    public class Car : First.ICar
    {
        public string Name { get; set; }
    }
}

问题是我无法访问源代码生成器中的引用项目。我尝试过使用反射:

namespace Second.Generator
{
    [Generator]
    public class MySourceGenerator : ISourceGenerator
    {
        public void Initialize(GeneratorInitializationContext context)
        {
        }

        public void Execute(GeneratorExecutionContext context)
        {
            var first = context.Compilation.References.First(); //this is First.dll

            var assembly = Assembly.LoadFrom(first.Display);
        }
    }
}

但我无法加载程序集:

无法加载文件或程序集 'file:///...First\bin\Debug\net6.0\ref\First.dll' 或 它的依赖项之一。不应加载参考程序集 执行。它们只能在 Reflection-only loader 中加载 上下文。

任何帮助将不胜感激。谢谢。

【问题讨论】:

    标签: c# sourcegenerators


    【解决方案1】:

    我已经找到了一些使用汇编符号的方法。使用反射不是一个好主意。

    namespace Second.Generator
    {
        [Generator]
        public class MySourceGenerator : ISourceGenerator
        {
            public void Initialize(GeneratorInitializationContext context)
            {
            }
    
            public void Execute(GeneratorExecutionContext context)
            {
                var types = context.Compilation.SourceModule.ReferencedAssemblySymbols.SelectMany(a =>
                {
                    try
                    {
                        var main = a.Identity.Name.Split('.').Aggregate(a.GlobalNamespace, (s, c) => s.GetNamespaceMembers().Single(m => m.Name.Equals(c)));
    
                        return GetAllTypes(main);
                    }
                    catch
                    {
                        return Enumerable.Empty<ITypeSymbol>();
                    }
                });
    
                var properties = types.Where(t => t.TypeKind == TypeKind.Interface && t.DeclaredAccessibility == Accessibility.Public).Select(t => new
                {
                    Interface = t,
                    Properties = t.GetMembers()
                });
            }
    
            private static IEnumerable<ITypeSymbol> GetAllTypes(INamespaceSymbol root)
            {
                foreach (var namespaceOrTypeSymbol in root.GetMembers())
                {
                    if (namespaceOrTypeSymbol is INamespaceSymbol @namespace) foreach (var nested in GetAllTypes(@namespace)) yield return nested;
    
                    else if (namespaceOrTypeSymbol is ITypeSymbol type) yield return type;
                }
            }
        }
    }
    

    【讨论】:

    • 如果从 Second 到 First 的引用是包引用,而不是项目引用,则此方法非常有效。有什么方法可以使这个项目引用也起作用?
    • @Abdelhakim 上面的代码也非常适合项目引用,现在通过在我的项目中使用这种方法进行了验证。
    猜你喜欢
    • 1970-01-01
    • 2021-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-09
    • 2016-01-05
    • 2011-01-25
    相关资源
    最近更新 更多