Common Compiler Infrastructure: How to work with ICustomAttribute
I'm attempting to use CCI-Metadata for creating a code generator, by iterating over a set of assemblies, discovering the types and their metadata and then generating the code. I would like to be able to control the code generation by attaching custom attributes to the metadata of the original types.
Something like:
[GenerateSpecialClass(true, "foo", IsReallySpecial=false)]
public class MyClass { ... }
I have a INamedTypeDefinition and get an IEnumerable from the Attributes property. From here, I can't figure out what to do to get the value of custom attribute and it's properties.
Could someone give 开发者_高级运维me a code sample: given an ICustomAttribute, how I can retrieve the values from my example attribute. Assume it's definition is:
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;
}
}
Any help would be very much appreciated. I assume I cast this to some other interface and do something magical on it; but I couldn't find a helper that did anything with it and don't fully understand the implementation/model hierarchy.
Try casting to Microsoft.Cci::IMetadataConstant
. Here's a sample code that dumps data out of 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
refers to name/value pairs in theValue
blob stream in metadata. They are used to specify fields and properties. For your class, CCI makesIsReallySpecial
available as anIMetadataNamedArgument
IMetadataExpression
refers to argument values of the constructor. So argsprop1
andprop2
are kept asMetadataExpression
in CCI object model.
Check out Jason Bock's Injectors. I think he does what you are looking for in his InjectorContext.Find() method and then the looks up the different properties/parameters in the NotNullInjector.OnInject() method.
Get his code up and running, then you'll have a better understanding of how to do what you're looking to do.
精彩评论