加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

如何使用代码生成动态创建C#方法?

发布时间:2020-12-15 06:35:15 所属栏目:百科 来源:网络整理
导读:为了在C中定义一个可由Lua调用的方法,它必须匹配给定的签名,并使用Lua API来检索参数并返回结果.我正在编写一个Lua的C#包装,我有兴趣可以调用任意的C#方法,而不使它们遵循这些约定.当以类似D的方式包装时,可以使用模板系统动态地为任何给定的方法创建粘合代
为了在C中定义一个可由Lua调用的方法,它必须匹配给定的签名,并使用Lua API来检索参数并返回结果.我正在编写一个Lua的C#包装,我有兴趣可以调用任意的C#方法,而不使它们遵循这些约定.当以类似D的方式包装时,可以使用模板系统动态地为任何给定的方法创建粘合代码.我认为这可能是C#中可能的,但是通过使用动态代码生成.

C API看起来像这样,生成的代码将通过我的库的较低级别的部分来操作,P / Invoke Lua C库.

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 .所以当从Lua调用C#函数时,它看起来像lua – >魔术包装功能 – >普通的C#函数.

谢谢.

解决方法

如果我明白你想要什么,似乎你有两个选择:

> use the CodeDOM在运行时生成并动态编译代码.
>发出实际的C#源代码,并在运行时将其动态编译成可调用的程序集.

CodeDom是一种毛茸茸的,很低级的代码来写.这个想法是有一个C#语言的对象模型.您首先实例化Code??TypeDeclaration – 这将生成一个类型或类.然后添加属性和字段 – 在这里,您可能会为p / invoke函数添加DllImport声明.然后,您将使用不同的CodeDOM添加方法到类型 – 这将是您插入生成的方法的位置.你可以让它公开,静态,无论你喜欢什么.

CodeDOM如下所示:

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);

...

它继续和.你可以看到,它变得很丑陋.然后你编译它,我没有显示.我假设你不想采取这种方法.

我发现CodeDom是非常crufty使用;相反,现在当我需要动态生成的程序集时,我将通过模板将实际的C#代码发送到内存中的一个字符串中,并进行编译.为我的目的简单得多编译如下所示:

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

在上面的代码中,LiteralSource包含要编译的源代码.正如我所说,我通过阅读模板并填写空白来产生.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读