Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding class members into specific locations using Roslyn?

Tags:

c#

roslyn

I am adding private fields into a class using ClassDeclarationSyntax.AddMembers method. Fields appear in the class, but I'd like to know how to add the fields into specific locations. As of now, they are added at the end of the class inside #if directive that happens to evaluate to true at the time of running the code generation.

Running the code:

var tree = SyntaxTree.ParseCompilationUnit(@"
namespace Test
{
    public class A
    {
#if !SILVERLIGHT
        public int someField;
#endif
    }
}");
var field =
    Syntax.FieldDeclaration(
        Syntax.VariableDeclaration(
            Syntax.PredefinedType(
                Syntax.Token(
                    SyntaxKind.StringKeyword))))
    .WithModifiers(Syntax.Token(SyntaxKind.PrivateKeyword))
    .AddDeclarationVariables(Syntax.VariableDeclarator("myAddedField"));
var theClass = tree.GetRoot().DescendantNodes()
    .OfType<ClassDeclarationSyntax>().First();
theClass = theClass.AddMembers(field).NormalizeWhitespace();
System.Diagnostics.Debug.Write(theClass.GetFullText());

will result in this:

public class A
{
#if !SILVERLIGHT
    public int someField;
    private string myAddedField;
#endif
}

And I would like to get this result:

public class A
{
    private string myAddedField;
#if !SILVERLIGHT
    public int someField;
#endif
}
like image 728
illodin Avatar asked Sep 12 '12 22:09

illodin


People also ask

How to set the setters of an attribute in Roslyn?

Note, that the setters of the attribute's properties are protected, so that the only way to set them is via the constructor. This was done on purpose in order to simplify parsing the attribute's information using Roslyn-now all we need to do-is to figure out which constructor argument corresponds to which attribute property.

How do I compile Roslyn code at runtime?

We can create source code and ask Roslyn to compile it at runtime. To do so, data structures to hold the necessary member information must be created. We have created a simple demo program to demonstrate this, using the DynamicProperty class to hold just new property names and types.

What is the best approach to build dynamic code in Roslyn?

Roslyn CaaS can be effectively used to build dynamic code enabling flexibility and type safety if the class to be build has at least a partially known structure. Measurements show that this hybrid approach holds a significant performance advantage over the fully dynamic ExpandoObject.

What is the Roslyn compilation object in simpleroslynanalysis?

This attribute is defined in the same project: SimpleRoslynAnalysis is a console project. Its main Program class contains all the samples. It utilizes extension methods from the static Extension class. Here is the code that we employ to obtain the Roslyn compilation object i.e. object that contains information about all the types:


1 Answers

To do this, you will have to locate where exactly do you want to place the new member and then modify the list of the class members accordingly. Something like:

private static SyntaxList<MemberDeclarationSyntax> AddBeforeIfDirective(
    SyntaxList<MemberDeclarationSyntax> oldMembers,
    MemberDeclarationSyntax newMember)
{
    var ifIndex = oldMembers.IndexOf(
        member => member.GetLeadingTrivia()
            .Any(t => t.Kind == SyntaxKind.IfDirective));
    return oldMembers.Insert(ifIndex, newMember);
}


…

var newMembers = AddBeforeIfDirective(theClass.Members, field);

theClass = theClass.WithMembers(newMembers).NormalizeWhitespace();
like image 62
svick Avatar answered Nov 15 '22 14:11

svick