如何更改C#控制台应用程序的入口点?

时间:2018-10-14 07:48:06

标签: c# .net clr cil csc

我想知道是否可以在以下示例中将.NET控制台应用程序入口点从Main更改为Main2方法:

class Program
{ 
    static void Main(string[] args)
    {
        Console.WriteLine("Main");
    }

    //desired entry point
    static void Main2(string[] args)
    {
        Console.WriteLine("Main2");
    }
}

我调查了这两个的IL代码。这是Main方法:

  .method private hidebysig static void 
    Main(
      string[] args
    ) cil managed 
  {
    .entrypoint
    .maxstack 8

    // other instructions

  } // end of method Program::Main

还有Main2方法:

.method private hidebysig static void 
    Main2(
      string[] args
    ) cil managed 
  {
    .maxstack 8

    //other instructions
  } // end of method Program::Main2

唯一的区别是.entrypoint方法中Main指令的正确性,据我所知,是在应用程序启动时由CLR检测到的。

是否有任何方法可以影响csc以此指令标记其他方法?其他编译器可以做到这一点吗?

编辑 我的问题与this one不同,因为我要问的是csc编译器(和其他编译器)的行为……尤其是如何将.entrypoint指令放在其他地方

4 个答案:

答案 0 :(得分:1)

该方法确实必须称为Main,但是您可以使用-main选项来指定哪个类的Main方法是入口点。

(使用Main作为入口是C#定义的一部分–在C#v5规范中,它在§3.1中,您也许可以克服,但您可以自己解决。 )

答案 1 :(得分:1)

这是不可能的,根据定义,Main是C#应用程序的入口点。

  

Main方法是C#应用程序的入口点。 (库和服务不需要Main方法作为入口点。)   应用程序启动后,Main方法是第一个方法,即   调用。

来源:MSDN

答案 2 :(得分:1)

入口点必须命名为Main,如C#语言规范§3.1所述:

  

3.1应用程序启动

     

应用程序启动 在执行环境调用指定方法时发生,该方法称为应用程序的条目   点。此入口点方法始终命名为Main,并且可以具有   以下签名之一:

static void Main() {...}
static void Main(string[] args) {...}
static int Main() {...}
static int Main(string[] args) {...}

看到单词“总是被命名为Main”吗?如果您通过编写另一个编译器将入口点更改为Main以外的其他名称,那么根据定义,该编译器将不是C#编译器。 :)

答案 3 :(得分:0)

这可以通过使用AssemblyBuilder库中的System.Reflection和其他内容来实现。

        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Save);

        TypeBuilder typeBuilder = assemblyBuilder
            .DefineDynamicModule("Module", "Test.exe", false)
            .DefineType("Program", TypeAttributes.Public);

        MethodBuilder methodBuilder = typeBuilder.DefineMethod("Main2", MethodAttributes.Public | MethodAttributes.Static);

        ILGenerator ilGenerator = methodBuilder.GetILGenerator();
        ilGenerator.EmitWriteLine("Main2");
        ilGenerator.Emit(OpCodes.Ret);

        assemblyBuilder.SetEntryPoint(methodBuilder);

        typeBuilder.CreateType();
        assemblyBuilder.Save("Test.exe");

这将产生以下IL代码(.entryPoint被放置在Main2方法上)

    .method public static 
       void Main2 () cil managed 
   {
       // Method begins at RVA 0x2050
       // Code size 11 (0xb)
       .maxstack 1
       .entrypoint

        IL_0000: ldstr "Main2"
        IL_0005: call void [mscorlib]System.Console::WriteLine(string)
        IL_000a: ret
   } // end of method Program::Main2

如果执行Test.exe,则会看到Main2方法已执行