Using Roslyn to parse/transform/generate code: am I aiming too high, or too low?

c#, code-generation, roslyn

Solution

If your requirement is parsing C# source code, then I think Roslyn is a good choice. And if you're going to use it for this part, I think it also makes sense to use it for code generations.

Code generation using Roslyn can be quite verbose (especially when compared with CodeDom), but I think that's not going to be a big issue for you.

I think `SyntaxRewriter` is best suited for making localized changes in code. But you're asking about parsing whole class and generating types based on that, I think for that, querying the syntax tree directly would work best.

For example, the simplest example of generating a read-only interface for all properties in a class could look something like this:

var originalClass =
    compilationUnit.DescendantNodes().OfType<ClassDeclarationSyntax>().Single();
string originalClassName = originalClass.Identifier.ValueText;
var properties =
    originalClass.DescendantNodes().OfType<PropertyDeclarationSyntax>();

var generatedInterface =
    SyntaxFactory.InterfaceDeclaration('I' + originalClassName)
          .AddMembers(
              properties.Select(
                  p =>
                  SyntaxFactory.PropertyDeclaration(p.Type, p.Identifier)
                        .AddAccessorListAccessors(
                            SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
                                  .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))))
                        .ToArray());

Problem

(What I'm trying to do is work around the Application.Settings/MVVM problem by generating an interface and wrapper class from the vs-generated settings file.) What I'd like to do is: - Parse a class declaration from file - Generate an interface declaration based on just the (non static) properties of the class - Generate a wrapper class which implements this interface, takes an instance of the original class in the constructor, and 'pipes' all the properties through to the instance. - Generate another class which implements the interface directly. My question is two-fold: - Am I barking up the wrong tree? Would I be better off using Code-Dom, T4, Regex(!) for this, or part of this? (I don't mind a bit of extra work, as this is mostly a learning experience.) - If Roslyn is the way to go, which bit of it should I be looking at? I was kind of naively hoping that there would be some way of walking the tree and spitting out just the bits that I want, but I'm having trouble getting my head round whether/how to use the SyntaxRewriter to do it, or whether to use a fluent-style construction, querying the source multiple times for the bits I need. If you want to comment on the MVVM aspect you can, but that's not the main thrust of the question :)

Original source

Related problems