2

I want to know if there is any good way of programmatically producing C# code without actually manipulating strings or StringBuilders. Additionally it should check if the code compiles, but I guess this can be done using CSharpCodeProvider.

I'm looking for something like the following:

CodeUnit unit = new CodeUnit();
unit.AddDefaultUsings();
unit.AddUsing("MyApi.CoolNameSpace", "MyApi.Yay");
var clazz = unit.AddClass("GeneratedClass", Access.Public);
clazz.AddConstructor("....");
if(unit.Compile() != true)
    //oh dang, somethings wrong!
else unit.WriteUTF8To("GeneratedClass.cs");

This might be part of the core library (Don't think CSharpCodeProvider can do this?) or an external library, but this is not my forte at all (dynamically producing code using c#), so if this seems clueless it's because I am!

1
  • 1
    What's wrong with strings? If you don't know the names of these things ahead of time I fail to see how you are going to use enumerated or constant values. Commented Jul 17, 2011 at 19:13

4 Answers 4

5

That's exactly what CodeDOM is for:

var unit = new CodeCompileUnit();

var @namespace = new CodeNamespace("GeneratedCode");
unit.Namespaces.Add(@namespace);

// AddDefault() doesn't exist, but you can create it as an extension method
@namespace.Imports.AddDefault();
@namespace.Imports.Add(new CodeNamespaceImport("MyApi.CoolNameSpace"));

var @class = new CodeTypeDeclaration("GeneratedClass");
@namespace.Types.Add(@class);

@class.TypeAttributes = TypeAttributes.Class | TypeAttributes.Public;

var constructor = new CodeConstructor();
constructor.Attributes = MemberAttributes.Public;
constructor.Parameters.Add(
    new CodeParameterDeclarationExpression(typeof(string), "name"));

constructor.Statements.Add(…);

@class.Members.Add(constructor);

var provider = new CSharpCodeProvider();

var result = provider.CompileAssemblyFromDom(new CompilerParameters(), unit);

Although it can be quite verbose. Also, it tries to be language-independent, which means you can't use C#-specific features like static classes, extension methods, LINQ query expressions or lambdas using this API. What you can do though, is to put any string inside method body. Using this, you can use some of the C#-specific features, but only using string manipulation, which you were trying to avoid.

Sign up to request clarification or add additional context in comments.

Comments

0

You can use Reflection.Emit classes like MethodBuilder. Also expression trees with them. It is rather CLS than C#.

Comments

0

I've done a wrapper around codedom. You only need to create your own C# script and specify the types being used. Namespaces and assemblies will automatically be included.

Example

public interface IWorld
{
    string Hello(string value);
}

string code = @"namespace MyNamespace
{
  class Temp : IWorld
  {
      public string Hello(string value)
      {
          return ""World "" + value;
      }
  }
}";

Compiler compiler = new Compiler();
compiler.AddType(typeof(string));
compiler.Compile(code);
var obj = compiler.CreateInstance<IWorld>();
string result = obj.Hello("World!");

Note that it was a long time ago that I wrote it. The example might not work 100%. (The Compiler class do work, the example might use it incorrectly).

Source code:

http://fadd.codeplex.com/SourceControl/changeset/view/67972#925984

Comments

0

I like to use the NVelocity Template Engine.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.