Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get attribute arguments with roslyn

Tags:

c#

.net

roslyn

I try to get the named arguments for MyAttribute with Roslyn.

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

However firstAttribute.AttributeClass.Kind equals to ErrorType and consequently firstAttribute.NamedArguments contains no elements.

The code isn't an anlyzer or something I have more complete context like a solution.

I can't see roslyn is missing any references or something else. What can I do to fully analyze the attribute?

like image 958
Florian Avatar asked Mar 06 '18 10:03

Florian


2 Answers

You need to fully qualify Attribute type name:

var sourceCode = (@"
    public class MyAttribute : System.Attribute // < here
    {
        public string Test { get; set; }
    }

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

Then it will work as you expect:

var firstNamedArg = firstAttribute.NamedArguments[0];
var key = firstNamedArg.Key; // "Test"
var value = firstNamedArg.Value.Value; // "Hello"

Alternatively, you can add using System; at the top:

var sourceCode = (@"
    using System;
    public class MyAttribute : Attribute
    {
        public string Test { get; set; }
    }

    [MyAttribute(Test = ""Hello"")]
    public class MyClass { }
");
like image 185
Evk Avatar answered Nov 05 '22 19:11

Evk


Instead of using the Roslyn's SemanticModel you can also simply use the Syntax API to get the atttribute's argument info:

        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"
like image 4
Ray Avatar answered Nov 05 '22 18:11

Ray