Cómo evaluar completamente los parámetros de un atributo en un generador de código fuente de C#?
En un generador de código fuente, encontré un atributo en una clase y resolví su FQN con GeneratorSyntaxContext.SemanticModel
para, por ejemplo, lidiar con el hecho de que su nombre se escriba con o sin “Attribute”. ¿Cómo puedo resolver los argumentos? Básicamente quiero manejar todos estos casos:
// class MyAttribute : Attribute
// {
// public MyAttribute(int first = 1, int second = 2, int third = 3) {...}
// string Property {get;set;}
// }
[My]
[MyAttribute(1)]
[My(second: 8 + 1)]
[My(third: 9, first: 9)]
[My(1, second: 9)]
[My(Property = "Bl" + "ah")] // Extra, puedo prescindir de esto, pero sería agradable
La mayoría del código que pude encontrar, incluidos los ejemplos oficiales, simplemente codifica en duro ArgumentList[0], [1], etc. y el nombre del atributo escrito en “forma corta”. Obtener el objeto del atributo en sí o una copia idéntica sería ideal (no está inyectado por el generador de código fuente, sino que se referencia de ProjectReferenced “normalmente”, por lo que el tipo está disponible), pero podría estar más allá de Roslyn, así que simplemente evaluar las constantes y averiguar qué valor va a dónde es suficiente.
davy.ai
Para resolver los argumentos de un atributo en un generador de código fuente, se puede usar el método
GetSymbolInfo
delSemanticModel
para obtener elIMethodSymbol
del constructor del atributo. Una vez que se tiene elIMethodSymbol
, se puede utilizar su propiedadParameters
para obtener información sobre los parámetros del constructor, incluyendo sus nombres y valores por defecto.Para manejar todas las diferentes formas en que se puede utilizar el atributo, se debe utilizar el
AttributeData
obtenido delSyntaxNode
que representa el atributo. Luego se puede iterar sobreAttributeData.ConstructorArguments
yAttributeData.NamedArguments
para obtener los valores de los argumentos en el orden en que fueron especificados o por sus nombres, respectivamente.Para manejar el caso de los argumentos con expresiones (como
Property = "Bl" + "ah"
), se puede utilizar elSemanticModel
para evaluar la expresión y obtener su valor resultante.En resumen, el proceso involucraría los siguientes pasos:
Obtener el
AttributeData
del atributo llamando aSemanticModel.GetSymbolInfo
en elSyntaxNode
que representa el atributo.Obtener el
IMethodSymbol
del constructor del atributo llamando aAttributeData.AttributeConstructor
.Obtener la lista de parámetros del constructor desde la propiedad
IMethodSymbol.Parameters
.Iterar sobre
AttributeData.ConstructorArguments
para obtener los argumentos ordenados. Para cada argumento, utilizar la propiedadValue
para obtener su valor. Si el argumento es una expresión, utilizar elSemanticModel
para evaluar la expresión y obtener su valor resultante.Iterar sobre
AttributeData.NamedArguments
para obtener los argumentos con nombres. Para cada argumento, utilizar la propiedadValue
para obtener su valor. Si el argumento es una expresión, utilizar elSemanticModel
para evaluar la expresión y obtener su valor resultante.Utilizar la información obtenida en los pasos 3-5 para manejar el atributo de la manera deseada.