c#属性超过main

有人问我一个关于如何打印的问题

line no 1 line no 2 line no 3 

不改变读取的主要方法

 static void Main(string[] args) { Console.WriteLine("line no 2"); } 

现在一种方法是为控制台应用程序提供多个入口点。 但是我尝试了另一种方法,如下所示:

 class Program { [Some] static void Main(string[] args) { Console.WriteLine("line no 2"); } } class SomeAttribute : Attribute { public SomeAttribute() { Console.WriteLine("line no 1"); } ~SomeAttribute() { Console.WriteLine("line no 3"); } } 

当我在每个WriteLine上应用断点时,我能够看到该方法有效,但是,控制台上没有反映出这一点。

只是好奇。

您可以将问题分解为钩子的搜索,这些钩子在控制台应用程序的Main方法执行之前和之后被触发。

  • 第一个钩子是一个Program静态构造函数,它保证在Program类的Main方法之前执行。

  • 第二个是AppDomain的事件ProcessExit , “当默认应用程序域的父进程退出时发生” 。 您可以使用静态构造函数来订阅此事件。


 class Program { static Program() { Console.WriteLine("line no 1"); AppDomain.CurrentDomain.ProcessExit += (s, a) => Console.WriteLine("line no 3"); } static void Main(string[] args) { Console.WriteLine("line no 2"); } } 

打印:

 line no 1 line no 2 line no 3 

下一部分将是一个很长的部分。 我将尝试解释您问题中SomeAttribute的问题。

首先,请考虑此StackOverflow问题以确切了解何时执行自定义属性构造函数 。 这并不是那么简单,乍看之下似乎也是如此。

我们已经知道,只有当你通过reflection访问它时,才会执行自定义属性的ctor。 所以在你的例子中,简单的程序执行不会触发属性构造函数。 但是,当您将SomeAttribute应用于Main方法时,为什么断点会被击中? 事实certificate,visual studio使用reflection来找出主要方法并将调试器附加到您的应用程序。 但是那时没有控制台窗口。 所以语句Console.WriteLine是无用的并且生效。 此外,它似乎阻止了控制台输出的所有下一个语句。

因此,下一代码将产生不同的结果,具体取决于您是否使用VS调试器运行它:

 class Program { [MyAttribute] static void Main() { } } class MyAttribute : Attribute { public MyAttribute() { MessageBox.Show("MyAttribute ctor"); } } 

如果你在没有调试器的情况下运行它(VS默认配置中的Ctrl + F5 ),你会看到,该程序终止并且没有窗口出现。 当你使用调试器( F5 )执行它时,你会看到

在此处输入图像描述

并且VS旁边没有控制台窗口,只有win表单图标: 在此处输入图像描述

正如我之前所描述的,当您尝试在没有人时写入控制台时,对Console.WriteLine所有其他调用都不会影响您的控制台应用程序。 这就是为什么你可以看到任何控制台消息,即使你在构造函数中执行断点。

我认为Ilya Ivanov的答案可能是最好的答案 。 不过也认为我的一个有趣的答案:

 public class Program { static Program() { Console.WriteLine("line no 1"); Console.WriteLine("line no 2"); Console.WriteLine("line no 3"); Environment.Exit(0); } static void Main(string[] args) { Console.WriteLine("line no 2"); } } 

让我们使用AOP,让我们利用PostSharp。 您将需要先下载并安装它 ,之后您需要使用NuGet添加对它的引用。 你必须安装它,因为它是编译器的钩子。 在编译代码时,请注意,PostSharp实际上会根据您使用的钩子将IL注入输出。

完成这两件事之后,为AOP属性添加一个新类:

 using PostSharp.Aspects; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication2 { [Serializable] public class ConsoleAspect : OnMethodBoundaryAspect { public override void OnEntry(MethodExecutionArgs args) { base.OnEntry(args); Console.WriteLine("line no 1"); } public override void OnExit(MethodExecutionArgs args) { base.OnExit(args); Console.WriteLine("line no 3"); } } } 

然后像这样修改您的Main方法:

 [ConsoleAspect] static void Main(string[] args) { Console.WriteLine("line no 2"); }