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