Skip to content

Repository files navigation

Testura Logo

Testura.Code is a wrapper around the Roslyn API and used for generation, saving and compiling C# code. It provides methods and helpers to generate classes, methods, statements and expressions.

It provide helpers to generate:

  • Classes
  • Methods
  • Parameters
  • Arguments
  • Attributes
  • Fields
  • Properties

But also simple statements like:

  • Declaration statements (for example declare and assign variables)
  • Iterations statements (for example for-loop)
  • Jump statements (for example return)
  • Selection statement (for example if-statements)
  • Expression statements (for example invoke methods)

Install

NuGet NuGet Status

https://www.nuget.org/packages/Testura.Code

PM> Install-Package Testura.Code

Usage

Testura.Code have three different types of helpers:

  • Generators - The most basic kinds of code generators, for example fields, properties and modifiers.
  • Statement - Helpers for regular statements and expressions, for example declare and assign a variable or invoke a method.
  • Builders - Currently we have two builder - One class builder and one method builder. These have the highest abstraction and are easy to use.

Documentation

Examples

Hello world

Here is an example on how to generate, save and compile a simple hello world.

Generate

var@class=newClassBuilder("Program","HelloWorld").WithUsings("System").WithModifiers(Modifiers.Public).WithMethods(newMethodBuilder("Main").WithModifiers(Modifiers.Public,Modifiers.Static).WithParameters(newParameter("args",typeof(string[]))).WithBody(BodyGenerator.Create(Statement.Expression.Invoke("Console","WriteLine",newList<IArgument>(){newValueArgument("Hello world")}).AsStatement(),Statement.Expression.Invoke("Console","ReadLine").AsStatement())).Build()).Build();

This code will generate following code:

usingSystem;namespaceHelloWorld{publicclassProgram{publicstaticvoidMain(String[]args){Console.WriteLine("Hello world");Console.ReadLine();}}}

Save

varsaver=newCodeSaver();// As a stringvargeneratedCode=saver.SaveCodeAsString(@class);// Or to filesaver.SaveCodeToFile(@class,@"/path/HelloWorld.cs");

Compile

varcompiler=newCompiler();//To a dll// From stringvarresult=awaitcompiler.CompileSourceAsync(@"/path/HelloWorld.dll",generatedCode);// From filevarresult=awaitcompiler.CompileFilesAsync(@"/path/HelloWorld.dll",@"/path/HelloWorld.cs");//In memory (without creating a dll)// From stringvarresult=awaitcompiler.CompileSourceInMemoryAsync(generatedCode);// From filevarresult=awaitcompiler.CompileFilesInMemoryAsync(@"/path/HelloWorld.cs");

More advanced examples

Model class

varclassBuilder=newClassBuilder("Cat","Models");var@class=classBuilder.WithUsings("System").WithConstructor(ConstructorGenerator.Create("Cat",BodyGenerator.Create(Statement.Declaration.Assign("Name",ReferenceGenerator.Create(newVariableReference("name"))),Statement.Declaration.Assign("Age",ReferenceGenerator.Create(newVariableReference("age")))),newList<Parameter>{newParameter("name",typeof(string)),newParameter("age",typeof(int))},newList<Modifiers>{Modifiers.Public})).WithProperties(PropertyGenerator.Create(newAutoProperty("Name",typeof(string),PropertyTypes.GetAndSet,newList<Modifiers>{Modifiers.Public})),PropertyGenerator.Create(newAutoProperty("Age",typeof(int),PropertyTypes.GetAndSet,newList<Modifiers>{Modifiers.Public}))).Build();

This code will generate following code:

usingSystem;namespaceModels{publicclassCat{publicCat(stringname,intage){Name=name;Age=age;}publicstringName{get;set;}publicintAge{get;set;}}}

Enum

var@class=newClassBuilder("Cat","Models").WithUsings("System").With(newEnumBuildMember("MyEnum",newList<EnumMember>{new("EnumValueOne",2,newAttribute[]{newAttribute("MyAttribute"),}),newEnumMember("EnumValueTwo")},newList<Modifiers>{Modifiers.Public})).Build();

This code will generate following code:

usingSystem;namespaceModels{publicclassCat{publicenumMyEnum{[MyAttribute]EnumValueOne=2,EnumValueTwo}}}

Class with file scoped namespace and body properties

var@class=newClassBuilder("Cat","Models",NamespaceType.FileScoped).WithUsings("System").WithFields(newField("_name",typeof(string),newList<Modifiers>(){Modifiers.Private}),newField("_age",typeof(int),newList<Modifiers>(){Modifiers.Private})).WithConstructor(ConstructorGenerator.Create("Cat",BodyGenerator.Create(Statement.Declaration.Assign("Name",ReferenceGenerator.Create(newVariableReference("name"))),Statement.Declaration.Assign("Age",ReferenceGenerator.Create(newVariableReference("age")))),newList<Parameter>{newParameter("name",typeof(string)),newParameter("age",typeof(int))},newList<Modifiers>{Modifiers.Public})).WithProperties(PropertyGenerator.Create(newBodyProperty("Name",typeof(string),BodyGenerator.Create(Statement.Jump.Return(newVariableReference("_name"))),BodyGenerator.Create(Statement.Declaration.Assign("_name",newValueKeywordReference())),newList<Modifiers>{Modifiers.Public})),PropertyGenerator.Create(newBodyProperty("Age",typeof(int),BodyGenerator.Create(Statement.Jump.Return(newVariableReference("_age"))),BodyGenerator.Create(Statement.Declaration.Assign("_age",newValueKeywordReference())),newList<Modifiers>{Modifiers.Public}))).Build();

This code will generate following code:

usingSystem;namespaceModels;publicclassCat{privatestring_name;privateint_age;publicCat(stringname,intage){Name=name;Age=age;}publicstringName{get{return_name;}set{_name=value;}}publicintAge{get{return_age;}set{_age=value;}}}

Record with primary constructor

varrecord=newRecordBuilder("Cat","Models",NamespaceType.FileScoped).WithUsings("System").WithPrimaryConstructor(newParameter("Age",typeof(int))).Build();

This code will generate following code:

usingSystem;namespaceModels;publicrecordCat(intAge);

Class with methods that override operators and comments

var@class=newClassBuilder("Cat","Models").WithUsings("System").WithMethods(newMethodBuilder("MyMethod").WithModifiers(Modifiers.Public,Modifiers.Static).WithOperatorOverloading(Operators.Increment).WithParameters(newParameter("MyParameter",typeof(string))).WithBody(BodyGenerator.Create(Statement.Declaration.Declare("hello",typeof(int)).WithComment("My comment above").WithComment("hej"),Statement.Declaration.Declare("hello",typeof(int)).WithComment("My comment to the side",CommentPosition.Right))).Build()).Build();

This code will generate following code:

usingSystem;namespaceModels{publicclassCat{publicstaticMyMethodoperator++(stringMyParameter){//hejinthello;inthello;//My comment to the side}}}

Test class with method references

var@class=newClassBuilder("NullTest","MyTest").WithUsings("System","NUnit.Framework").WithModifiers(Modifiers.Public).WithMethods(newMethodBuilder("SetUp").WithAttributes(newAttribute("SetUp")).WithModifiers(Modifiers.Public).Build(),newMethodBuilder("Test_WhenAddingNumber_ShouldBeCorrectSum").WithAttributes(newAttribute("Test")).WithModifiers(Modifiers.Public).WithBody(BodyGenerator.Create(Statement.Declaration.Declare("myList",typeof(List<int>)),NunitAssertGenerator.Throws(newVariableReference("myList",newMethodReference("First")),typeof(ArgumentNullException)))).Build()).Build();

This code will generate following code:

usingSystem;usingNUnit.Framework;namespaceMyTest{publicclassNullTest{[SetUp]publicvoidSetUp(){}[Test]publicvoidTest_WhenAddingNumber_ShouldBeCorrectSum(){List<int>myList;Assert.Throws<ArgumentNullException>(()=>myList.First(),"");}}}

Missing anything?

If we miss a feature, syntax or statements - just create an issue or contact us and I'm sure we can add it.

It is also possible for you to contribute with your own feature. Simply add a pull request and we will look at it.

License

This project is licensed under the MIT License. See the LICENSE.md file for details.

Contact

Visit www.testura.net, twitter at @testuranet or email at mille.bostrom@testura.net

About

Testura.Code is a wrapper around the Roslyn API and used for generation, saving and compiling C# code. It provides methods and helpers to generate classes, methods, statements and expressions.

Topics

Resources

Contributing

Stars

298 stars

Watchers

11 watching

Forks

Releases

Packages

Used by

Contributors

Languages