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
}
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.
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.
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.
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:
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With