Общая инфраструктура компилятора: как работать с ICustomAttribute
Я пытаюсь использовать CCI-метаданные для создания генератора кода, перебирая наборы сборок, обнаруживая типы и их метаданные, а затем генерируя код. Я хотел бы иметь возможность контролировать генерацию кода, прикрепляя настраиваемые атрибуты к метаданным исходных типов.
Что-то вроде:
[GenerateSpecialClass(true, "foo", IsReallySpecial=false)]
public class MyClass { ... }
У меня есть INamedTypeDefinition и я получаю IEnumerable из свойства Attributes. Отсюда я не могу понять, что делать, чтобы получить значение пользовательского атрибута и его свойств.
Может ли кто-нибудь дать мне пример кода: с помощью атрибута ICustomAttribute, как я могу получить значения из моего примера атрибута. Предположим, это определение:
public GenericSpecialClassAttribute : Attribute
{
public bool Prop1 { get; set; }
public string Prop2 {get; set; }
public bool IsReallySpecial {get; set; }
public GenericSpecialClassAttribute(bool prop1, string prop2)
{
Prop1 = prop1;
Prop2 = prop2;
}
}
Любая помощь будет очень высоко ценится. Я предполагаю, что приведу это к какому-то другому интерфейсу и сделаю что-то магическое с ним но я не смог найти помощника, который бы что-нибудь делал с ним и не полностью понимал иерархию реализации / модели.
2 ответа
Попробуйте привести к Microsoft.Cci::IMetadataConstant
, Вот пример кода, который выводит данные из Microsoft.Cci::ICustomAttribute
,
public static void parseCustomAttribute(Cci::ICustomAttribute customAttribute)
{
foreach (Cci::IMetadataNamedArgument namedArg in customAttribute.NamedArguments)
{
parseNamedArgument(namedArg);
}
foreach (Cci::IMetadataExpression arg in customAttribute.Arguments)
{
parseFixedArgument(arg);
}
Console.WriteLine("Type Reference:\t\t"+ customAttribute.Type.ToString());
var constructor = customAttribute.Constructor as Cci::IMethodDefinition;
if (constructor != null)
{
//parseMethodDefinition(constructor);
}
else
{
//parseMethodReference(constructor);
}
}
private static void parseFixedArgument(Cci::IMetadataExpression fixedArgument)
{
Console.WriteLine("Type Reference:\t\t" + fixedArgument.Type.ToString());
var constValue = fixedArgument as Cci::IMetadataConstant;
if (constValue != null)
{
Console.WriteLine("Value :" + constValue.Value);
}
}
private static void parseNamedArgument(Cci::IMetadataNamedArgument namedArg)
{
Console.WriteLine("Name:" + "\t\t" + namedArg.ArgumentName.Value);
parseFixedArgument(namedArg.ArgumentValue);
}
IMetadataNamedArgument
относится к парам имя / значение вValue
поток больших двоичных объектов в метаданных. Они используются для указания полей и свойств. Для вашего класса CCI делаетIsReallySpecial
доступны какIMetadataNamedArgument
IMetadataExpression
ссылается на значения аргумента конструктора. Итак, аргументыprop1
а такжеprop2
хранятся какMetadataExpression
в объектной модели CCI.
Проверьте инжекторы Джейсона Бока. Я думаю, что он делает то, что вы ищете в своем методе InjectorContext.Find(), а затем просматривает различные свойства / параметры в методе NotNullInjector.OnInject().
Запустите его код, и вы лучше поймете, как делать то, что вы хотите сделать.