BuildableExpressions and BuildableExpressions.Generator work via creation of
SourceCodeExpression
s, which can be compiled to CLR Types at runtime or used to generate C# source
code files at build-time. A SourceCodeExpression
consists of one or more types.
Defining an Attribute
To add an attribute to your SourceCodeExpression
, use:
BuildableExpression.SourceCode(sc =>
{
sc.AddAttribute("MyAttribute", attr =>
{
// Set attribute options if desired:
// attr.SetSummary("Attribute description");
// attr.AddAttribute<SomeAttribute>();
// attr.SetAbstract();
// attr.SetSealed();
// attr.SetPartial();
// Add attribute members - see below
});
});
Members are added via the attribute API, which supports:
- Documentation
- Constructors
- Fields
- Properties
- Methods
- Attributes (applying attributes to an Attribute)
- Interface implementation
- Inheritance
Setting Attribute Usage
To customise to which targets an attribute can be applied, use:
BuildableExpression.SourceCode(sc =>
{
// Add an attribute which can only be applied to
// classes, structs or interfaces:
sc.AddAttribute("TypesOnlyAttribute", attr =>
{
// Set one or more AttributeTargets values:
attr.SetValidOn(
AttributeTargets.Class |
AttributeTargets.Struct |
AttributeTargets.Interface);
});
});
Applying Attributes
To apply an Attribute, use the following - normal CLR attributes can be applied as well as Attributes you define in a SourceCodeExpression:
BuildableExpression.SourceCode(sc =>
{
// Make an empty marker attribute:
var myAttribute = sc.AddAttribute("MarkerAttribute");
sc.AddClass("AttributedClass", cls =>
{
// Mark AttributedClass with the MarkerAttribute:
cls.AddAttribute(myAttribute);
// Add an int field:
cls.AddField<int>("AttributedField", f =>
{
// Mark AttributedField with the MarkerAttribute:
f.AddAttribute(myAttribute);
});
// Add a string get/set auto property:
cls.AddProperty<string>("AttributedAutoProperty", p =>
{
// Mark AttributedAutoProperty with the
// System.ComponentModel.DataAnnotations.RequiredAttribute:
p.AddAttribute<RequiredAttribute>();
});
// Add a string get-only property:
cls.AddProperty<int>("AttributedGetOnlyProperty", p =>
{
// Set the property's getter:
p.SetGetter(gtr =>
{
// Mark AttributedGetOnlyProperty getter
// with the MarkerAttribute:
gtr.AddAttribute<RequiredAttribute>();
// Set the AttributedGetOnlyProperty getter's body:
gtr.SetBody(Expression.Constant(123));
});
});
// Add a method:
cls.AddMethod("AttributedMethod", m =>
{
// Mark AttributedMethod with the MarkerAttribute:
m.AddAttribute(myAttribute);
// Add an int parameter:
m.AddParameter<int>("intValue", p =>
{
// Mark the intValue parameter with the MarkerAttribute:
p.AddAttribute(myAttribute);
});
// Set the method body:
m.SetBody(Expression.Empty());
});
});
});
Attribute Constructors
To apply an Attribute with a constructor, use:
BuildableExpression.SourceCode(sc =>
{
// Create an attribute with a single
// string constructor parameter:
var nameAttribute = sc.AddAttribute("NameAttribute", attr =>
{
// Add the constructor:
attr.AddConstructor(ctor =>
{
// Add the constructor parameter:
ctor.AddParameter<string>("name");
// Add an empty constructor body
// (just for this example):
ctor.SetBody(Expressions.Empty());
});
});
// Add a class to which to apply the attribute:
sc.AddClass("HasANameAttribute", cls =>
{
// Apply the attribute:
cls.AddAttribute(nameAttribute, attr =>
{
// Set the constructor argument to pass
// to the NameAttribute:
attr.SetConstructorArguments("Dennis");
});
});
});