I have an Attribute
class used to decorate an assembly for use in C# source code generators. I am trying to get the value of one of the arguments that is type System.Type. I can get the values of the other properties just fine.
Here's the attribute class:
[AttributeUsage(AttributeTargets.Assembly)]
public class MigrationFunctionAttribute : Attribute
{
public Type MigrationFunction { get; set; }
public string MigrationMethod { get; set; }
public string DependsOn { get; set; }
public string SqlScriptBucket { get; set; }
// ATTRIBUTE: ADD HERE
public string Branch { get; set; }
}
Here's my usage of the attribute:
[assembly: MigrationFunction(MigrationFunction = typeof(MigrationFunctions), MigrationMethod = nameof(MigrationFunctions.MyMigrator), Branch = "@Branch", DependsOn = "Restore")]
After receiving the attribute in the SyntaxReceiver
, I try to build a model from the information:
public static AttributeModel2<IMigrationFunctionAttributeModel> Build(AttributeSyntax receiverMigrationFunctionAttribute, GeneratorExecutionContext context)
{
SemanticModel semanticModel = context.Compilation.GetSemanticModel(receiverMigrationFunctionAttribute.SyntaxTree);
foreach (var attributeArgumentSyntax in receiverMigrationFunctionAttribute.ArgumentList.Arguments)
{
switch (attributeArgumentSyntax.NameEquals.Name.Identifier.ValueText)
{
case nameof(MigrationFunctionAttribute.MigrationFunction):
Debug.WriteLine(attributeArgumentSyntax.Expression);
// ^^^ outputs 'typeof(MigrationFunctions)'
TypeInfo t = semanticModel.GetTypeInfo(attributeArgumentSyntax.Expression);
Debug.WriteLine(t.Type.ToDisplayString());
// ^^^ outputs 'System.Type'
/// HOW DO I GET THE TYPE HERE, which should be "MigrationFunctions", not "System.Type"???
break;
case nameof(MigrationFunctionAttribute.Branch):
var value = semanticModel.GetConstantValue(attributeArgumentSyntax.Expression);
Debug.WriteLine(value.Value);
// ^^^ outputs '@Branch just fine
break;
}
}
return null;
}
The model builder method can pick through the arguments as expected, but I cannot figure out how to get the correct type info for the property:
public Type MigrationFunction { get; set; }
I get System.Type
, whereas I am expecting to get MigrationFunctions
.
When I output from, I get typeof(MigrationFunctions)
:
Debug.WriteLine(attributeArgumentSyntax.Expression);
As documented in the code, HOW DO I GET THE TYPE HERE, which should be "MigrationFunctions", not "System.Type"???
You're definitely on the right track. Let's home in on this part:
TypeInfo t = semanticModel.GetTypeInfo(attributeArgumentSyntax.Expression);
Debug.WriteLine(t.Type.ToDisplayString());
// ^^^ outputs 'System.Type'
As you note, GetTypeInfo
when invoked with attributeArgumentSyntax.Expression
returns a TypeInfo
representing System.Type
. This makes sense because the declared type of that attribute property is System.Type
.
You can still get the type you're after (MigrationFunctions
) but you have to dig a little deeper. First cast the expression to TypeOfExpressionSyntax
:
var typeOfExpression = (TypeOfExpressionSyntax)attributeArgumentSyntax.Expression;
With that you can get the actual TypeSyntax
representing typeof(MigrationFunctions)
:
var typeSyntax = typeOfExpression.Type;
Finally, you can get the ITypeSymbol
for MigrationFunctions
:
var type = semanticModel.GetTypeInfo(typeSyntax);