Для определения метода в C, который является вызываемым Lua, он должен соответствовать данной подписи и использовать API Lua для получения результатов возврата и параметров. Я пишу обертку C# Lua, и я интересуюсь способностью назвать произвольные методы C#, не заставляя их следовать этим конвенциям. При обертывании в чем-то как D можно было бы использовать шаблонную систему для динамичного создания этого кода связующего звена для любого данного метода. Я думал, что это могло бы быть возможно также в C#, но при помощи динамической генерации кода.
API C выглядит примерно так, и сгенерированный код управлял бы этим через более низкую часть уровня моей библиотеки который P/Invokes библиотека 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#, отразить его параметры и возвращать значения, генерировать (или получить от кэша), метод, который использует API Lua как вышеупомянутый, чтобы передать те параметры и возвратить те типы возврата и наконец продвинуть тот метод к Lua. Таким образом, когда функция C# вызвана от Lua, это смотрит что-то как lua-> волшебная функция обертки-> обычная функция C#.
Спасибо.
Если я понимаю, что вы хотите, у вас есть 2 варианта:
CodeDom - это довольно сложный для написания код очень низкого уровня. Идея в том, что для языка C # существует объектная модель. Вы начинаете с создания экземпляра CodeTypeDeclaration - это сгенерирует тип или класс. Затем вы добавляете свойства и поля - здесь вы, вероятно, добавите объявления DllImport
для ваших функций p / invoke. Затем вы используете разные методы добавления 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 довольно непростым в использовании; вместо этого теперь, когда мне нужны динамически генерируемые сборки, я испущу реальный код 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
содержит исходный код для компиляции. Как я уже сказал, я генерирую это, читая шаблон и заполняя пробелы.
Я не уверен, что правильно интерпретирую ваш вопрос, но вы можете взглянуть на прокси Castle.Dynamic. Он позволяет вам создавать прокси для классов и интерфейсов, а затем перехватывать определенные вызовы методов (что-либо вообще в интерфейсе и что-либо виртуальное в реальном классе). Когда вы перехватываете вызов, вы можете просто посмотреть аргументы и перенаправить вызов в lua API через P-Invoke. Здесь есть отличный учебник .
Вы можете раскрыть ваш C# как COM, что позволит вызывать все (публичные) методы внешними приложениями.
Или же вы можете представить одну функцию C#, которая будет вызывать соответствующую другую функцию, возможно, жестко закодированную для списка фактических функций в C#, или, возможно, использующую отражение. Она может принимать массив произвольного размера для параметров.
Попробуйте поискать в T4 . Поскольку он изначально является частью Visual Studio, вы можете использовать среду отражения, чтобы найти все методы в соответствии с вашими вопросами. Поищите в Google, и я уверен, что вы сможете найти образец кода или шаблона людей, использующих отражение с T4 уже для создания классов или методов оболочки.