Code Generation with Roslyn – Fields and Properties

I’m going to give a few more basic examples of code generation with Roslyn. The following assume that you have a ClassGenerationSyntax variable named “@class”. The examples have also shortened SyntaxFactory to SF using:

using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

Properties

The code

// Add a property
PropertyDeclarationSyntax @property = SF.PropertyDeclaration( SF.ParseTypeName( "String" ), "MyProperty"  )
    .AddModifiers( SF.Token( SyntaxKind.PublicKeyword ) );
// Add a getter
@property = @property.AddAccessorListAccessors(
    SF.AccessorDeclaration( SyntaxKind.GetAccessorDeclaration )
        .WithSemicolonToken( SF.Token(SyntaxKind.SemicolonToken ) 
        ) );
// Add a private setter
@property = @property.AddAccessorListAccessors( 
    SF.AccessorDeclaration( SyntaxKind.SetAccessorDeclaration )
    .AddModifiers( SF.Token( SyntaxKind.PrivateKeyword ) )
    .WithSemicolonToken( SF.Token(SyntaxKind.SemicolonToken ) 
    ) );
// Add the property to the class
@class = @class.AddMembers( @property );

Produces the code:

public class MyClass {
    public String MyProperty { get; private set; }
}

Variables

This adds a simple field to the class:

FieldDeclarationSyntax aField = SF.FieldDeclaration( 
    SF.VariableDeclaration( 
        SF.ParseTypeName( "String" ), 
        SF.SeparatedList(new [] { SF.VariableDeclarator( SF.Identifier( "_a" ) ) } )
    ) )
    .AddModifiers( SF.Token( SyntaxKind.PrivateKeyword ) );
@class = @class.AddMembers( aField );

Generating the code:

private String _a;

This code initializes the field to a new object:

ExpressionSyntax initializationExpression = SF.ObjectCreationExpression(
    SF.Token( SyntaxKind.NewKeyword ),
    SF.ParseTypeName( "OtherClass" ),
    SF.ArgumentList( SF.SeparatedList<ArgumentSyntax>( new [] {
        SF.Argument( SF.LiteralExpression( SyntaxKind.NumericLiteralExpression, SF.Literal( 1 ) ) ),
        SF.Argument( SF.LiteralExpression( SyntaxKind.StringLiteralExpression, SF.Literal( "abc" ) ) )
    } ) ),
    null
    );
FieldDeclarationSyntax bField = SF.FieldDeclaration( 
    SF.VariableDeclaration( 
        SF.ParseTypeName( "OtherClass" ), 
        SF.SeparatedList(new [] {
            SF.VariableDeclarator(
                SF.Identifier( "_b" ),
                null,
                SF.EqualsValueClause( initializationExpression ) 
            )
        } )
    ) )
    .AddModifiers( SF.Token( SyntaxKind.PrivateKeyword ) )
    .AddModifiers( SF.Token( SyntaxKind.ReadOnlyKeyword ) )
    ;
@class = @class.AddMembers( bField );

Generating the code:

private readonly OtherClass _b = new OtherClass(1, "abc");

Field-backed Properties

The following code generates a getter and setter backed by a field:

PropertyDeclarationSyntax property =
    SF.PropertyDeclaration( SF.ParseTypeName( "String" ), SF.Identifier( "A" ) )
        .AddModifiers( SF.Token( SyntaxKind.PublicKeyword ) )
        .AddAccessorListAccessors( 
            SF.AccessorDeclaration(
                SyntaxKind.GetAccessorDeclaration,
                SF.Block(
                    SF.List( new [] {
                        SF.ReturnStatement( SF.IdentifierName( "_a" ) )
                    } )
                )
            ),
            SF.AccessorDeclaration(
                SyntaxKind.SetAccessorDeclaration,
                SF.Block( 
                    SF.List( new [] {
                        SF.ExpressionStatement( 
                            SF.BinaryExpression( 
                                SyntaxKind.SimpleAssignmentExpression,
                                SF.IdentifierName( "_a" ),
                                SF.IdentifierName( "value" )
                            )
                        )
                    } )
                )
            )
        )
    ;

Producing the following code:

public String A {
    get {
        return _a;
    }

    set {
        _a = value;
    }
}

The ratio of code to output shows that it would be a lot easier to generate code from scratch with TextWriter.