使用 Roslyn 获取程序集属性



我希望能够使用 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();
}

目前,我只是通过硬编码定位程序集属性来作弊。 再次对ArgumentList进行硬编码以获得其中的第一个表达式。 这让我得到 str1 和 str2 的结果"Test1"

有没有办法只是说,给我类型TestAttribute1的属性,然后说,给我名为TheValue的属性的值?

你可以

实现,只需尝试从IAssemblySymbol获取属性,这个符号可以从Compilation中衍生:

var attribute = compilation.Assembly.GetAttributes().FirstOrDefault(x => x.AttributeClass.ToString() == "Helloworld.TestAttribute1");
if(!(attribute is null))
{
    var ctorArgs = attribute.ConstructorArguments;
    var propArgs = attribute.NamedArguments;
}

ctorArgspropArgsTypedConstant项的集合(propArgs字典(,TypedConstant具有属性Value(如果是数组时Values(,它将传递的值保留为 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 static IEnumerable<MetadataReference> GetGlobalReferences()
{
    var assemblies = new[]
    {
        typeof(System.Object).Assembly, //mscorlib
    };
    var refs = from a in assemblies
        select MetadataReference.CreateFromFile(a.Location);
    return refs.ToList();
}
<</div> div class="one_answers">

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

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();

相关内容

最新更新