简体   繁体   English

以编程方式生成 C# 代码文件的干净、高效、可靠的方法

[英]Clean, efficient, infallible method of programmatically generating C# code files

I want to know if there is any good way of programmatically producing C# code without actually manipulating strings or StringBuilders.我想知道是否有任何好的方法可以在不实际操作字符串或 StringBuilders 的情况下以编程方式生成 C# 代码。 Additionally it should check if the code compiles, but I guess this can be done using CSharpCodeProvider.此外,它应该检查代码是否编译,但我想这可以使用 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!这可能是核心库的一部分(不认为 CSharpCodeProvider 可以做到这一点?)或外部库,但这根本不是我的强项(使用 c# 动态生成代码),所以如果这看起来毫无头绪,那是因为我是!

That's exactly what CodeDOM is for:这正是 CodeDOM 的用途:

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.此外,它试图独立于语言,这意味着您不能使用 static 类、扩展方法、LINQ 查询表达式或使用此 ZDB974238714CA8DE1434A7CE1DZ08A 的 lambdas 等特定于 C# 的功能。 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.使用它,您可以使用一些 C# 特定的功能,但只能使用您试图避免的字符串操作。

I like to use the NVelocity Template Engine .我喜欢使用NVelocity 模板引擎

You can use Reflection.Emit classes like MethodBuilder .您可以使用MethodBuilder类的 Reflection.Emit 类。 Also expression trees with them.还带有它们的表达式树。 It is rather CLS than C#.它是 CLS 而不是 C#。

I've done a wrapper around codedom.我已经对 codedom 做了一个包装。 You only need to create your own C# script and specify the types being used.您只需创建自己的 C# 脚本并指定使用的类型。 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%.该示例可能无法 100% 工作。 (The Compiler class do work, the example might use it incorrectly). (编译器 class 确实可以工作,示例可能使用不正确)。

Source code:源代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM