C# 使用Roslyn获取程序集属性

C# 使用Roslyn获取程序集属性,c#,attributes,roslyn,C#,Attributes,Roslyn,我希望能够使用Roslyn代码分析从程序集中的AssemblyInfo.cs文件中读取一些程序集属性 因此,给出以下示例: using System; using System.Collections.Generic; using System.Text; [assembly: Helloworld.TestAttribute1("Test1")] [assembly: Helloworld.TestAttribute1(TheValue = "Test1", IgnoreThis = "I

我希望能够使用Roslyn代码分析从程序集中的AssemblyInfo.cs文件中读取一些程序集属性

因此,给出以下示例:

using System;
using System.Collections.Generic;
using System.Text;

[assembly: Helloworld.TestAttribute1("Test1")]
[assembly: Helloworld.TestAttribute1(TheValue = "Test1", IgnoreThis = "I dont want this one!")]

namespace Helloworld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
        }
    }

    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
    public class TestAttribute1 : Attribute
    {
        public TestAttribute1()
        {
        }

        public TestAttribute1(string theValue)
        {
            this.TheValue = theValue;
        }

        public string TheValue { get; set; }

        public string IgnoreThis { get; set; }
    }
}
我希望能够提取类型为
TestAttribute1
的属性和名为
TheValue
的已定义属性的值

在本例中定义了两次-第一次使用构造函数参数,另一次使用命名参数

我有以下代码:

static void Main(string[] args)
{
        string cs = GetFile();

        SyntaxTree tree = CSharpSyntaxTree.ParseText(cs);

        var root = (CompilationUnitSyntax)tree.GetRoot();
        var compilation = CSharpCompilation.Create("").AddSyntaxTrees(tree);
        var model = compilation.GetSemanticModel(tree);

        // get the attributes

        AttributeSyntax attr1 = root.DescendantNodes()
                .OfType<AttributeSyntax>().ToArray()[0];
        AttributeSyntax attr2 = root.DescendantNodes()
                .OfType<AttributeSyntax>().ToArray()[1];

        var ex1 = attr1.ArgumentList.Arguments.FirstOrDefault().Expression as LiteralExpressionSyntax;
        var str1 = ex1.GetText().ToString();

        var ex2 = attr2.ArgumentList.Arguments.FirstOrDefault().Expression as LiteralExpressionSyntax;
        var str2 = ex2.GetText().ToString();

}
static void Main(字符串[]args)
{
字符串cs=GetFile();
SyntaxTree-tree=CSharpSyntaxTree.ParseText(cs);
var root=(CompilationUnitSyntax)tree.GetRoot();
var compilation=csharpcomilation.Create(“”).AddSyntaxTrees(树);
var model=compilation.GetSemanticModel(树);
//获取属性
AttributeSyntax attr1=root.degenantNodes()
.OfType().ToArray()[0];
AttributeSyntax attr2=root.degenantNodes()
.OfType().ToArray()[1];
var ex1=attr1.ArgumentList.Arguments.FirstOrDefault().Expression作为LiteralExpressionSyntax;
var str1=ex1.GetText().ToString();
var ex2=attr2.ArgumentList.Arguments.FirstOrDefault().Expression作为LiteralExpressionSyntax;
var str2=ex2.GetText().ToString();
}
目前我只是通过硬编码定位程序集属性来作弊。再次硬编码
参数列表
,以获取其中的第一个表达式。这使我得到str1和str2的结果为
\“Test1\”


是否有一种方法可以说,给我类型
TestAttribute1
的属性,然后说,给我名为
TheValue
的属性的值?

为了获得给定类型的属性,以下代码将起作用:

Func<AttributeSyntax, bool> findAttribute = (a) =>
{
    var typeInfo = model.GetTypeInfo(a).ConvertedType;
    return typeInfo.Name == "TestAttribute1" && typeInfo.ContainingNamespace.Name == "Helloworld";
};

AttributeSyntax[] attrs = root.DescendantNodes()
    .OfType<AttributeSyntax>()
    .Where(findAttribute)
    .ToArray();
Func findAttribute=(a)=>
{
var typeInfo=model.GetTypeInfo(a).ConvertedType;
返回typeInfo.Name==“TestAttribute1”&&typeInfo.ContainingNamespace.Name==“Helloworld”;
};
AttributeSyntax[]attrs=root.degenantNodes()
第()类
.何处(findAttribute)
.ToArray();

为了获得给定类型的属性,以下代码将起作用:

Func<AttributeSyntax, bool> findAttribute = (a) =>
{
    var typeInfo = model.GetTypeInfo(a).ConvertedType;
    return typeInfo.Name == "TestAttribute1" && typeInfo.ContainingNamespace.Name == "Helloworld";
};

AttributeSyntax[] attrs = root.DescendantNodes()
    .OfType<AttributeSyntax>()
    .Where(findAttribute)
    .ToArray();
Func findAttribute=(a)=>
{
var typeInfo=model.GetTypeInfo(a).ConvertedType;
返回typeInfo.Name==“TestAttribute1”&&typeInfo.ContainingNamespace.Name==“Helloworld”;
};
AttributeSyntax[]attrs=root.degenantNodes()
第()类
.何处(findAttribute)
.ToArray();

您只需尝试从
IAssemblySymbol
获取属性即可实现此目的,此符号可从
编译中检索:

var attribute = compilation.Assembly.GetAttributes().FirstOrDefault(x => x.AttributeClass.ToString() == "Helloworld.TestAttribute1");
if(!(attribute is null))
{
    var ctorArgs = attribute.ConstructorArguments;
    var propArgs = attribute.NamedArguments;
}
TypedConstant
propArgs
TypedConstant
项的集合(
propArgs
是字典),并且
TypedConstant
具有属性
Value
(或
Value
,当其为数组时)将传递的值保留为ctor参数或属性值。最后,您只需要使用
TypedConstant.Type
筛选您感兴趣的参数

这应该如下所示:

SyntaxTree tree = CSharpSyntaxTree.ParseText(cs);

var root = (CompilationUnitSyntax)tree.GetRoot();
var compilation = CSharpCompilation.Create("test").AddSyntaxTrees(tree);

// get references to add
compilation = compilation.AddReferences(GetGlobalReferences());

var model = compilation.GetSemanticModel(tree);

var attrs = compilation.Assembly.GetAttributes().Where(x => x.AttributeClass.ToString() == "Helloworld.TestAttribute1");

foreach (var attr in attrs)
{
    var ctorArgs = attr.ConstructorArguments;
    var propArgs = attr.NamedArguments;
}
private静态IEnumerable GetGlobalReferences()
{
var assemblies=new[]
{
typeof(System.Object).Assembly,//mscorlib
};
var refs=来自部件中的
选择MetadataReference.CreateFromFile(a.Location);
返回refs.ToList();
}

您只需尝试从
IAssemblySymbol
获取属性即可实现此目的,此符号可从
编译中检索:

var attribute = compilation.Assembly.GetAttributes().FirstOrDefault(x => x.AttributeClass.ToString() == "Helloworld.TestAttribute1");
if(!(attribute is null))
{
    var ctorArgs = attribute.ConstructorArguments;
    var propArgs = attribute.NamedArguments;
}
TypedConstant
propArgs
TypedConstant
项的集合(
propArgs
是字典),并且
TypedConstant
具有属性
Value
(或
Value
,当其为数组时)将传递的值保留为ctor参数或属性值。最后,您只需要使用
TypedConstant.Type
筛选您感兴趣的参数

这应该如下所示:

SyntaxTree tree = CSharpSyntaxTree.ParseText(cs);

var root = (CompilationUnitSyntax)tree.GetRoot();
var compilation = CSharpCompilation.Create("test").AddSyntaxTrees(tree);

// get references to add
compilation = compilation.AddReferences(GetGlobalReferences());

var model = compilation.GetSemanticModel(tree);

var attrs = compilation.Assembly.GetAttributes().Where(x => x.AttributeClass.ToString() == "Helloworld.TestAttribute1");

foreach (var attr in attrs)
{
    var ctorArgs = attr.ConstructorArguments;
    var propArgs = attr.NamedArguments;
}
private静态IEnumerable GetGlobalReferences()
{
var assemblies=new[]
{
typeof(System.Object).Assembly,//mscorlib
};
var refs=来自部件中的
选择MetadataReference.CreateFromFile(a.Location);
返回refs.ToList();
}

Hmm,出于某种原因,如果我运行
属性.ConstructorArguments
attr.NamedArguments
为空。如果我遍历而不是遍历FirstOrDefault,则这两个属性都是相同的。注意:此示例使用的是dotnetcore 2.2。@Andez,假设问题是编译不知道
TestAttribute1
是属性,因为编译没有对系统库的引用:
mscrolib
system
system.Core
。因此,如果我运行
属性.ConstructorArguments
attr.NamedArguments
为空,请尝试添加它们。如果我遍历而不是遍历FirstOrDefault,则这两个属性都是相同的。注意:此示例使用的是dotnetcore 2.2。@Andez,假设问题是编译不知道
TestAttribute1
是属性,因为编译没有对系统库的引用:
mscrolib
system
system.Core
。所以试着添加它们