2013-03-24 2 views
1

Я пишу конкатенативный язык в C#, и в настоящее время он интерпретируется, но я хочу сделать следующий шаг: компиляция. Для начала я попытался написать простой «Hello, World!». программа, использующая System.Reflection.Emit. Код работает без каких-либо исключений испускают, но когда я запускаю созданный файл «test.exe», он бросает исключениеReflection.Emit: AssemblyBuilder.SetEntryPoint не устанавливает точку входа

Unhandled Exception: System.MissingMethodException: Entry point not found in assembly 'IL_Test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. 

я пытался прибегая к помощи для ответа, но безрезультатно. Может, кто-то здесь может мне помочь? (Пожалуйста) код, который я написал ниже:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 
using System.Reflection.Emit; 
using System.IO; 
using System.Diagnostics; 

namespace ILCompileTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      const string ASSEMBLY_NAME = "IL_Test"; 

      AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
       new AssemblyName(ASSEMBLY_NAME), AssemblyBuilderAccess.Save); 
      ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(
       ASSEMBLY_NAME); 
      TypeBuilder typeBuilder = moduleBuilder.DefineType("Program", 
       TypeAttributes.Class | TypeAttributes.Public); 
      MethodBuilder methodBuilder = typeBuilder.DefineMethod(
       "Main", MethodAttributes.Public | MethodAttributes.Static, 
       typeof(void), new Type[] { typeof(string[]) }); 
      ILGenerator gen = methodBuilder.GetILGenerator(); 

      gen.Emit(OpCodes.Ldstr, "Hello, World!"); 
      gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); 
      gen.Emit(OpCodes.Ldc_I4_1); 
      gen.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadKey", new Type[] { typeof(bool) })); 

      assemblyBuilder.SetEntryPoint(methodBuilder, PEFileKinds.ConsoleApplication); 
      File.Delete("test.exe"); 
      assemblyBuilder.Save("test.exe"); 

      Process.Start("test.exe"); 
     } 
    } 
} 

Итак, вопрос: как я могу установить точку входа к главному методу я определяю?

ответ

1

У вас отсутствует вызов типаBuilder.CreateType(), . DefineDynamicModule должен иметь имя exe, переданное как второй параметр. Полный рабочий образец:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 
using System.Reflection.Emit; 
using System.IO; 
using System.Diagnostics; 

namespace ILCompileTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      const string ASSEMBLY_NAME = "IL_Test"; 

      AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
       new AssemblyName(ASSEMBLY_NAME), AssemblyBuilderAccess.Save); 
      ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(
       ASSEMBLY_NAME, "test.exe"); 
      TypeBuilder typeBuilder = moduleBuilder.DefineType("Program", 
       TypeAttributes.Class | TypeAttributes.Public); 
      MethodBuilder methodBuilder = typeBuilder.DefineMethod(
       "Main", MethodAttributes.HideBySig|MethodAttributes.Public | MethodAttributes.Static, 
       typeof(void), new Type[] { typeof(string[]) }); 
      ILGenerator gen = methodBuilder.GetILGenerator(); 

      gen.Emit(OpCodes.Ldstr, "Hello, World!"); 
      gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); 
      gen.Emit(OpCodes.Ldc_I4_1); 
      gen.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadKey", new Type[] { typeof(bool) })); 
      typeBuilder.CreateType(); 
      assemblyBuilder.SetEntryPoint(methodBuilder, PEFileKinds.ConsoleApplication); 
      File.Delete("test.exe"); 
      assemblyBuilder.Save("test.exe"); 

      Process.Start("test.exe"); 
     } 
    } 
} 
+0

Спасибо! Это исправило это! Я также узнал, что мне нужно Opcodes.Pop возвращаемое значение Console.ReadKey и команда Opcodes.Ret, чтобы заставить все работать. – feralin

+0

Вы знаете, почему ModuleBuilder хочет имя файла? Нужно ли быть таким же, как значение, которое я передаю AssemblyBuilder.Save()? – feralin

+0

Я считаю, что это связано с плохим выбором перегрузок для DefineDynamicModule - согласно MSDN, две перегрузки создают переходные процессы, а два создают устойчивый модуль. Имя файла должно быть одинаковым, иначе приложение также потерпит неудачу. Указание имени файла в двух местах происходит от возможности создания сборки из нескольких модулей/файлов. – Alexander