如何使用code代动态创建C#的方法呢? [英] How to use code generation to dynamically create C# methods?
问题描述
为了在C是可调用的Lua它具有以匹配给定的签名,并使用的Lua API检索的参数和返回结果中定义的方法。我正在写一个C#包装的Lua,我感兴趣的是能够调用任意的C#方法,而没有让他们遵循这些约定。当东西如D包裹,人们可能会使用模板系统,动态地创建这种胶code对于任何给定的方法。我想这可能是可能的,以及在C#中,但通过使用动态code一代。
In order to define a method in C that is callable by Lua it has to match a given signature and use the Lua API to retrieve parameters and return results. I'm writing a C# wrapper of Lua and I'm interested in being able to call arbitrary C# methods without making them follow these conventions. When wrapping in something like D, one might use the template system to dynamically create this glue code for any given method. I was thinking this might be possible as well in C#, but by using dynamic code generation.
在C API看起来像这样,产生的code将通过我的图书馆水平较低的一部分P /调用的Lua的C库操纵这一点。
The C API looks something like this, and the generated code would manipulate this through a lower level part of my library which P/Invokes the Lua C library.
static int foo (lua_State *L)
{
int n = lua_gettop(L); /* number of arguments */
lua_Number sum = 0;
int i;
for (i = 1; i <= n; i++)
{
if (!lua_isnumber(L, i))
{
lua_pushstring(L, "incorrect argument");
lua_error(L);
}
sum += lua_tonumber(L, i);
}
lua_pushnumber(L, sum/n); /* first result */
lua_pushnumber(L, sum); /* second result */
return 2; /* number of results */
}
所以基本上的思路是采取一个C#方法,体现其参数和返回值,生成(或从缓存中检索),它使用Lua的API,像上面的方法来传递这些参数和返回的返回类型,最后推送方法到Lua。因此,当C#函数从Lua称为它看起来像卢阿 - >魔法包装函数 - >普通的C#功能
So basically the idea is to take a C# method, reflect its parameters and return values, generate (or retrieve from cache) a method that uses the Lua API like above to pass those parameters and return those return types and finally push that method to Lua. So when C# function is called from Lua it looks something like lua -> magic wrapper function -> ordinary C# function.
感谢。
推荐答案
如果我理解你想要什么,看来你有2个选项:
If I understand what you want, it seems you have 2 options:
- 使用codeDOM 生成和动态编译code,在运行时。
- 在实际发射的C#源$ C $ C,并动态地把它编译成一个可调用的组件在运行时。
- use the CodeDOM to generate and dynamically compile code, at runtime.
- emit actual C# source code, and dynamically compile it into a callable assembly at runtime.
codeDOM是有点毛茸茸的,很低级的code写的。这个想法是有一个为C#语言的对象模型。你开始通过实例化codeTypeDeclaration - 这将产生一个类型或类。然后添加属性和字段 - 在这里你可能会添加的DllImport
声明您的P / Invoke功能。然后,可以使用不同的codeDOM添加方法的类型 - 这将是在那里你会插入生成的方法。你可以把它公开,静态的,不管你喜欢。
CodeDom is sort of hairy, very low-level code to write. The idea is there's an object model for the C# language. You start by instantiating a CodeTypeDeclaration - this will generate a type or class. Then you add properties and fields - here you would likely add DllImport
declarations for your p/invoke functions. Then you use different CodeDOM add methods to the type - this would be where you'd insert the generated method. You could make it public, static, whatever you like.
codeDOM看起来是这样的:
CodeDOM looks like this:
System.Type mt= a[0].GetType();
System.CodeDom.CodeTypeDeclaration class1 = new System.CodeDom.CodeTypeDeclaration(mt.Name);
class1.IsClass=true;
class1.TypeAttributes = System.Reflection.TypeAttributes.Public;
class1.Comments.Add(new System.CodeDom.CodeCommentStatement("Wrapper class for " + mt.Name));
System.CodeDom.CodeConstructor ctor;
ctor= new System.CodeDom.CodeConstructor();
ctor.Attributes = System.CodeDom.MemberAttributes.Public;
ctor.Comments.Add(new System.CodeDom.CodeCommentStatement("the null constructor"));
class1.Members.Add(ctor);
ctor.Statements.Add(new System.CodeDom.CodeAssignStatement(new System.CodeDom.CodeVariableReferenceExpression("m_wrapped"), new System.CodeDom.CodeObjectCreateExpression(mt)));
ctor= new System.CodeDom.CodeConstructor();
ctor.Attributes = System.CodeDom.MemberAttributes.Public;
ctor.Comments.Add(new System.CodeDom.CodeCommentStatement("the 'copy' constructor"));
class1.Members.Add(ctor);
ctor.Parameters.Add(new System.CodeDom.CodeParameterDeclarationExpression(mt,"X"));
ctor.Statements.Add(new System.CodeDom.CodeAssignStatement(new System.CodeDom.CodeVariableReferenceExpression("m_wrapped"), new System.CodeDom.CodeVariableReferenceExpression("X")));
// embed a local (private) copy of the wrapped type
System.CodeDom.CodeMemberField field1;
field1= new System.CodeDom.CodeMemberField();
field1.Attributes = System.CodeDom.MemberAttributes.Private;
field1.Name= "m_wrapped";
field1.Type=new System.CodeDom.CodeTypeReference(mt);
class1.Members.Add(field1);
...
如此下去。而上。正如你所看到的,它得到pretty的丑陋。再后来,你编译它,我并没有显示。我假设你不会想要采取这种方式。
it goes on. and on. As you can see, it gets pretty ugly. Then later you compile it, which I did not show. I'm assuming you're not gonna want to take this approach.
我发现codeDOM是pretty的这些混沌使用;相反,现在当我需要动态生成的程序集,我会的散发出实际的C#code 的,通常是通过模板,为一个字符串在内存中,并编译的是的。这是我的目的要简单得多。编译如下:
I found CodeDom to be pretty crufty to use; instead, now when I need dynamically-generated assemblies, I will emit actual C# code, normally via templates, into a string in memory, and compile that. It's much simpler for my purposes. The compilation looks like this:
var cp = new System.CodeDom.Compiler.CompilerParameters {
ReferencedAssemblies.Add(filesystemLocation), // like /R: option on csc.exe
GenerateInMemory = true, // you will get a System.Reflection.Assembly back
GenerateExecutable = false, // Dll
IncludeDebugInformation = false,
CompilerOptions = ""
};
var csharp = new Microsoft.CSharp.CSharpCodeProvider();
// this actually runs csc.exe:
System.CodeDom.Compiler.CompilerResults cr =
csharp.CompileAssemblyFromSource(cp, LiteralSource);
// cr.Output contains the output from the command
if (cr.Errors.Count != 0)
{
// handle errors
}
System.Reflection.Assembly a = cr.CompiledAssembly;
// party on the type here, either via reflection...
System.Type t = a.GetType("TheDynamicallyGeneratedType");
// or via a wellknown interface
在上面的code, LiteralSource
包含源$ C $ C进行编译。正如我所说,我产生这种通过阅读模板,填写空白。
In the above code, LiteralSource
contains the source code to be compiled. As I said, I generate this by reading a template and filling in the blanks.
这篇关于如何使用code代动态创建C#的方法呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!