首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用roslyn获取属性参数

使用roslyn获取属性参数
EN

Stack Overflow用户
提问于 2018-03-06 10:54:28
回答 3查看 5.6K关注 0票数 7

我试图用Roslyn获得MyAttribute的命名参数。

代码语言:javascript
复制
var sourceCode = (@"
    public class MyAttribute : Attribute
    {
        public string Test { get; set; }
    }

    [MyAttribute(Test = ""Hello"")]
    public class MyClass { }
");

var syntaxTree = CSharpSyntaxTree.ParseText(sourceCode);
var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var compilation = CSharpCompilation.Create("MyCompilation", new[] { syntaxTree }, new[] { mscorlib });
var semanticModel = compilation.GetSemanticModel(syntaxTree);

var syntaxRoot = syntaxTree.GetRoot();
var classNode = syntaxRoot.DescendantNodes().OfType<ClassDeclarationSyntax>().Skip(1).First();
var classModel = (ITypeSymbol)semanticModel.GetDeclaredSymbol(classNode);
var firstAttribute = classModel.GetAttributes().First();

但是,firstAttribute.AttributeClass.Kind等于ErrorType,因此firstAttribute.NamedArguments不包含任何元素。

代码不是anlyzer或者其他什么东西,我有更完整的上下文,比如解决方案。

我看不出罗斯林漏掉了什么推荐信什么的。我能做些什么来充分分析属性呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-03-06 11:02:06

您需要完全限定Attribute类型名称:

代码语言:javascript
复制
var sourceCode = (@"
    public class MyAttribute : System.Attribute // < here
    {
        public string Test { get; set; }
    }

    [MyAttribute(Test = ""Hello"")]
    public class MyClass { }
");

然后,它将如您所期望的那样工作:

代码语言:javascript
复制
var firstNamedArg = firstAttribute.NamedArguments[0];
var key = firstNamedArg.Key; // "Test"
var value = firstNamedArg.Value.Value; // "Hello"

或者,您可以在顶部添加using System;

代码语言:javascript
复制
var sourceCode = (@"
    using System;
    public class MyAttribute : Attribute
    {
        public string Test { get; set; }
    }

    [MyAttribute(Test = ""Hello"")]
    public class MyClass { }
");
票数 9
EN

Stack Overflow用户

发布于 2018-03-20 20:29:47

与使用Roslyn的SemanticModel不同,您还可以简单地使用语法API获取atttribute的参数信息:

代码语言:javascript
复制
        var firstAttribute = classNode.AttributeLists.First().Attributes.First();
        var attributeName = firstAttribute.Name.NormalizeWhitespace().ToFullString();
        Console.WriteLine(attributeName);
        // prints --> "MyAttribute"

        var firstArgument = firstAttribute.ArgumentList.Arguments.First();

        var argumentFullString = firstArgument.NormalizeWhitespace().ToFullString();
        Console.WriteLine(argumentFullString);
        // prints --> Test = "Hello"

        var argumentName = firstArgument.NameEquals.Name.Identifier.ValueText;
        Console.WriteLine(argumentName);
        // prints --> Test

        var argumentExpression = firstArgument.Expression.NormalizeWhitespace().ToFullString();
        Console.WriteLine(argumentExpression);
        // prints --> "Hello"
票数 4
EN

Stack Overflow用户

发布于 2021-12-26 11:47:50

一旦您拥有了您的xxxDeclaredSymbol,您就可以获得如下所有属性

代码语言:javascript
复制
var attributes = methodSymbol.GetAttributes().ToArray();

然后可以循环遍历数组中的每个AttributeData,并使用我编写的扩展,它将给出传递给属性的构造函数的所有名称+值的列表,不管它们是否命名.

代码语言:javascript
复制
// Used as a 3 value tuple for Name + TypeName + actual value
public class NameTypeAndValue
{
    public string Name { get; private set; }
    public string TypeFullName { get; private set; }
    public object Value { get; private set; }

    public NameTypeAndValue(string name, string typeFullName, object value)
    {
        Name = name;
        TypeFullName = typeFullName;
        Value = value;
    }
}

public static class ITypeSymbolExtensions
{
    // Converts names like `string` to `System.String`
    public static string GetTypeFullName(this ITypeSymbol typeSymbol) =>
        typeSymbol.SpecialType == SpecialType.None
        ? typeSymbol.ToDisplayString()
        : typeSymbol.SpecialType.ToString().Replace("_", ".");
}

public static bool TryGetAttributeAndValues(
    this AttributeData attributeData,
    string attributeFullName,
    SemanticModel model,
    out IEnumerable<NameTypeAndValue> attributeValues)
{
    var attributeValuesList = new List<NameTypeAndValue>();
    var constructorParams = attributeData.AttributeConstructor.Parameters;

    // Start with an indexed list of names for mandatory args
    var argumentNames = constructorParams.Select(x => x.Name).ToArray();

    var allArguments = attributeData.ConstructorArguments
        // For unnamed args, we get the name from the array we just made
        .Select((info, index) => new KeyValuePair<string, TypedConstant>(argumentNames[index], info))
        // Then we use name + value from the named values
        .Union(attributeData.NamedArguments.Select(x => new KeyValuePair<string, TypedConstant>(x.Key, x.Value)))
        .Distinct();

    foreach(var argument in allArguments)
    {
        attributeValuesList.Add(
            new NameTypeAndValue(
                name: argument.Key,
                typeFullName: argument.Value.Type.GetTypeFullName(),
                value: argument.Value.Value));
    }
    attributeValues = attributeValuesList.ToArray();
    return true;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49129099

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档