Dogs Chasing Squirrels

A software development blog

Category Archives: Software Development

Functional programming with F#

0

In an episode of the .NET Rocks podcast, guest Bryan Hunter describes his experience analyzing a large object-oriented code base. It’s a good listen. The problems with it were the same problems you see with all large O-O code bases, he says. But one module was a complete surprise because…there were no problems. The application had zero downtime in 4 years of operation. The team was even able to do “hot loading” to deploy updates while the application was running. What was the difference? This module was written in Erlang, a functional language.

The life of a software engineer - cartoon

Life of a software engineer. I believe the original source is http://www.bonkersworld.net/building-software/

Whenever you build an enterprise-scale project, you will find yourself using a bare minimum of libraries and patterns such that despite your best intentions – or even because of your best intentions – your solution will be complex and tricky to maintain from moment one. It’s a terrible life we lead where following best practices feels bad and wrong. Functional programming may be the answer.

I’ve begun to learn .NET’s own functional programming language, F#. I wouldn’t call the language mainstream, but it’s not a toy, either. It’s completely compatible with the rest of the .NET class library so one can make WPF or ASP.NET MVC applications with it. I hope that it will one day lead to a more satisfying experience developing enterprise applications.

Some F# learning resources:

TFS team adding colorizer features

0

It looks like the TFS team are adding colorization features to the TFS board. Hopefully this will make my colorizer plugin obsolete.

Outlook Add-In for Replicon

5

My employer uses Replicon to track hours against projects and tasks. Its web-based user interface is…adequate. Entering time in an online calendar is fine but I already have an electronic calendar open all day: Microsoft Outlook.

I started a project to create an add-in that adds an “Add to Replicon” menu item to the Outlook calendar. The Replicon Repliconnect API is used to get project and task information and to send the timesheet information back to the server.

It’s still a work in progress. The initial code is up here.

Fault-safe WCF Proxy Generator for Service Reference clients

0

WCF is great, but if a connection ever throws an exception for any reason it puts the client in the Faulted state and the client has to be aborted and recreated. It’s a pain in the ass since this can happen anywhere a client method is called.
In a previous post, I showed the dynamic generation of a proxy for a WCF channel.

Nowadays, I suspect most people create their clients using “Add Service Reference”. This generates a ClientBase client that suffers from the same problem as raw channels – if there’s ever an exception, you need to recreate the instance.

Following the earlier post, I created code to use the CIL Emit libraries to dynamically generate a fault-tolerant proxy around a given client. If an exception is thrown, the client is recreated with the correct authentication and whatever settings were used to construct it in the first place.
The code is up on github.

Code Generation with Roslyn – If, Else, and Loops

1

if statements

This:

MethodDeclarationSyntax method = SF.MethodDeclaration(
    SF.PredefinedType( SF.Token( SyntaxKind.VoidKeyword ) ),
    "MyMethod"
    )
    .AddModifiers( SF.Token( SyntaxKind.PublicKeyword ) )
    .AddBodyStatements( 
        SF.IfStatement(
            SF.BinaryExpression( 
                SyntaxKind.EqualsExpression,
                SF.IdentifierName( "_a" ),
                SF.LiteralExpression( SyntaxKind.NumericLiteralExpression, SF.Literal( "X" ) )
            ),
            SF.Block(  
            )
        )
    )
    ;

Will get you this:

public void MyMethod() {
    if (_a == "X") {
    }
}

if-else statements

This:

MethodDeclarationSyntax method = SF.MethodDeclaration(
    SF.PredefinedType( SF.Token( SyntaxKind.VoidKeyword ) ),
    "MyMethod"
    )
    .AddModifiers( SF.Token( SyntaxKind.PublicKeyword ) )
    .AddBodyStatements( 
        SF.IfStatement(
            SF.BinaryExpression( 
                SyntaxKind.EqualsExpression,
                SF.IdentifierName( "_a" ),
                SF.LiteralExpression( SyntaxKind.NumericLiteralExpression, SF.Literal( "X" ) )
            ),
            SF.Block(  
            ),
            SF.ElseClause( 
                SF.Token( SyntaxKind.ElseKeyword ),
                SF.IfStatement( 
                    SF.BinaryExpression( 
                        SyntaxKind.EqualsExpression,
                        SF.IdentifierName( "_a" ),
                        SF.LiteralExpression( SyntaxKind.NumericLiteralExpression, SF.Literal( "Y" ) )
                    ),
                    SF.Block(  
                    ),
                    SF.ElseClause(
                        SF.Token( SyntaxKind.ElseKeyword ),
                        SF.Block( 
                        )
                    )
                )
            )
        )
    )

Will get you this:

public void MyMethod() {
    if (_a == "X") {
    }
    else if (_a == "Y") {
    }
    else {
    }
}

for loops

This:

MethodDeclarationSyntax method = SF.MethodDeclaration(
    SF.PredefinedType( SF.Token( SyntaxKind.VoidKeyword ) ),
    "MyMethod"
    )
    .AddModifiers( SF.Token( SyntaxKind.PublicKeyword ) )
    .AddBodyStatements( 
        SF.ForStatement(
            SF.VariableDeclaration( 
                SF.PredefinedType( SF.Token( SyntaxKind.IntKeyword ) ), 
                SF.SeparatedList(new [] {
                    SF.VariableDeclarator(
                        SF.Identifier( "i" ),
                        null,
                        SF.EqualsValueClause( SF.LiteralExpression( SyntaxKind.NumericLiteralExpression, SF.Literal( 0 ) ) ) 
                    )
                } )
            ),
            SF.SeparatedList<ExpressionSyntax>(),
            SF.BinaryExpression( 
                SyntaxKind.LessThanExpression,
                SF.IdentifierName( "i" ),
                SF.LiteralExpression( SyntaxKind.NumericLiteralExpression, SF.Literal( 10 ) )
            ),
            SF.SeparatedList<ExpressionSyntax>( new [] {
                SF.PostfixUnaryExpression(
                    SyntaxKind.PostIncrementExpression,
                    SF.IdentifierName( "i" )
                )
            } ),
            SF.Block(  
            )
        )
    )

Will get you this:

public void MyMethod() {
    for (int i = 0; i < 10; i++) {
    }
}

foreach loops

This defines our generic list:

LocalDeclarationStatementSyntax listDeclaration = SF.LocalDeclarationStatement(
    SF.TokenList(),
    SF.VariableDeclaration( 
        SF.GenericName( 
            SF.Identifier( "IList" ), 
            SF.TypeArgumentList( 
                SF.SeparatedList<TypeSyntax>( new [] { SF.PredefinedType( SF.Token( SyntaxKind.StringKeyword ) ) } ) 
            ) 
        ), 
        SF.SeparatedList( new [] {
            SF.VariableDeclarator(
                SF.Identifier( "list" ),
                null,
                SF.EqualsValueClause( 
                    SF.ObjectCreationExpression(
                        SF.Token( SyntaxKind.NewKeyword ),
                        SF.GenericName( 
                            SF.Identifier( "List" ), 
                            SF.TypeArgumentList( 
                                SF.SeparatedList<TypeSyntax>( new [] { SF.PredefinedType( SF.Token( SyntaxKind.StringKeyword ) ) } ) 
                            ) 
                        ),
                        SF.ArgumentList( SF.SeparatedList<ArgumentSyntax>( new ArgumentSyntax[0] ) ),
                        null
                    )
                )
            )
        } )
    )
);

And this our “foreach”:

ForEachStatementSyntax forEachStatement = SF.ForEachStatement(
    SF.PredefinedType( SF.Token( SyntaxKind.StringKeyword ) ),
    SF.Identifier( "item" ),
    SF.IdentifierName( "list" ),
    SF.Block()
);

Adding both to a method:

MethodDeclarationSyntax method = SF.MethodDeclaration(
    SF.PredefinedType( SF.Token( SyntaxKind.VoidKeyword ) ),
    "MyMethod"
    )
    .AddModifiers( SF.Token( SyntaxKind.PublicKeyword ) )
    .AddBodyStatements( 
        listDeclaration,
        forEachStatement
    );

Will get you this:

public void MyMethod() {
    IList<string> list = new List<string>();
    foreach (string item in list) {
    }
}

while loops

This is one of the more straightforward ones.
This:

MethodDeclarationSyntax method = SF.MethodDeclaration(
    SF.PredefinedType( SF.Token( SyntaxKind.VoidKeyword ) ),
    "MyMethod"
    )
    .AddModifiers( SF.Token( SyntaxKind.PublicKeyword ) )
    .AddBodyStatements( 
        SF.WhileStatement( 
            SF.LiteralExpression( SyntaxKind.TrueLiteralExpression ),
            SF.Block(  
                SF.BreakStatement()
            )
        )
    );

Will get you this:

public void MyMethod() {
    while (true) {
        break;
    }
}

Code Generation with Roslyn – Fields and Properties

0

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.

Formatting C# with Roslyn

2

There’s already been a change to Roslyn that made my last bit of code obsolete. CustomWorkspace no longer requires a string in the constructor and is just:

new CustomWorkspace()

I found out how to change the formatting on the output. We can do this:

CustomWorkspace cw = new CustomWorkspace();
OptionSet options = cw.GetOptions();
options = options.WithChangedOption( CSharpFormattingOptions.OpenBracesInNewLineForMethods, false );
options = options.WithChangedOption( CSharpFormattingOptions.OpenBracesInNewLineForTypes, false );
SyntaxNode formattedNode = Formatter.Format( cu, cw, options );

With this change, our output code is now:

using System;
using System.Generic;

namespace MyNamespace {
    private partial class MyClass {
    }
}

Generating Code with Roslyn

6

Roslyn, now known as the .NET Compiler Platform, essentially provides a DOM for C# and Visual Basic. What it means for code generation is that you can construct an object representing your C# class and Roslyn will generate the .cs file.
This is the first in what I hope to be a series of posts showing how to generate particular elements. This will be for my own reference, if nothing else, but some may find it useful.

Preparing your Project

You’ll have to add the following references, probably using NuGet:

  • Microsoft.CodeAnalysis
  • Microsoft.CodeAnalysis.CSharp
  • Microsoft.CodeAnalysis.CSharp.Workspaces
  • Microsoft.CodeAnalysis.Workspaces
  • Microsoft.CSharp

Just search NuGet for “CodeAnalysis” and you’ll find them.

Generating Classes from Scratch

The first thing I tried to do with Roslyn was to create an empty class from scratch but I couldn’t find any documentation online for how to do it. Every example I saw started by parsing an existing .cs file and making changes to it. So here’s how you do it.
Any file is considered a Compilation Unit. You can declare one like this:

CompilationUnitSyntax cu = SF.CompilationUnit()

And what’s the first thing in a .cs file? The “using”s. Add them like this:

CompilationUnitSyntax cu = SF.CompilationUnit()
    .AddUsings( SF.UsingDirective( SF.IdentifierName( "System" ) ) )
    .AddUsings( SF.UsingDirective( SF.IdentifierName( "System.Generic" ) ) )
    ;

The most important thing to note here is that all Roslyn objects are immutable. So saying:

cu.AddUsings( SF.UsingDirective( SF.IdentifierName( "System" ) ) )

Isn’t going to get you anywhere. AddUsings doesn’t change the cu object; It returns a new CompilationUnitSyntax with the change. You would have to write:

cu = cu.AddUsings( SF.UsingDirective( SF.IdentifierName( "System" ) ) )

So in Roslyn examples you’ll often see people chaining all their code together. I avoid it because it becomes unreadable and unmaintainable.
Next we’ll add a namespace:

NamespaceDeclarationSyntax ns = SF.NamespaceDeclaration( SF.IdentifierName( "MyNamespace" ) );
cu = cu.AddMembers( ns );

Now we’ll add our type to the namespace. We’ll declare it as a partial, private class.

ClassDeclarationSyntax c = SF.ClassDeclaration( "MyClass" )
    .AddModifiers( SF.Token( SyntaxKind.PrivateKeyword ) )
    .AddModifiers( SF.Token( SyntaxKind.PartialKeyword ) )
    ;
ns = ns.AddMembers( c );

Finally, we’ll write our type out to a file using the SyntaxTree type. This will write to any TextWriter (like StreamWriter). Here I write it out to a StringBuilder. Note that I have to specify a filename anyway (“C:\out.cs”, below). It doesn’t get used.

SyntaxNode formattedNode = Formatter.Format( cu, new CustomWorkspace( "Host" ) );
StringBuilder sb = new StringBuilder();
using ( StringWriter writer = new StringWriter( sb ) ) {
    formattedNode.WriteTo( writer );
}

And here’s what our class looks like:

using System;
using System.Generic;

namespace MyNamespace
{
    private partial class MyClass
    {
    }
}

Amazing.
I’ll have to figure out how to do something about the opening braces being on new lines. I don’t like putting opening braces on new lines.

[Edit 2015-08-23: See this update for some changes to Roslyn object names since this was first posted]

Test utilities

0

I put some MSTest-based unit testing utilities up on github.  So far I have FileAssert and DirectoryAssert classes that compare the contents of, as you would expect, files and directories. I do a lot of code generation and so it’s useful to be able to compare files and directories easily.  I did some extra work so that when files and directories are different, the message that comes back is helpful and identifies the lines and character positions that differ.  This is something you don’t get when simply comparing strings.

TFS Colorizer Stats

9

colorizer - chrome stats

As a developer, I can see some statistics about how my plugins are doing.  The Chrome extension is actually doing pretty well.  It’s getting about 11 downloads a week which is pretty good given that I haven’t really promoted it anywhere.

TFS Colorizer in the FIrefox Review Queue

My Firefox add-in is still in review.  When I submitted it to Mozilla almost two weeks ago I was asked if I wanted the 3-day preliminary review or the 10-day full review.  I picked the quick 3-day review.  you wouldn’t know it.  I moved from 57th place yesterday to 54th today.  Maybe they’re all watching the World Cup.  Maybe they’re in the World Cup.  Who knows.