c#属性超过main

use*_*247 9 c# attributes console.writeline

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

line no 1
line no 2
line no 3
Run Code Online (Sandbox Code Playgroud)

不改变读取的主要方法

static void Main(string[] args)
{
    Console.WriteLine("line no 2");
}
Run Code Online (Sandbox Code Playgroud)

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

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

只是好奇.

Ily*_*nov 15

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

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

  • 二是事件ProcessExitAppDomain,其中"时默认应用程序域的父进程退出时".您可以使用静态构造函数来订阅此事件.


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");
    }
}
Run Code Online (Sandbox Code Playgroud)

打印:

line no 1
line no 2
line no 3
Run Code Online (Sandbox Code Playgroud)

下一部分将是一个很长的部分.我会试着解释你问题SomeAttribute中的问题.

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

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

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

class Program
{
    [MyAttribute]
    static void Main()
    {

    }
}

class MyAttribute : Attribute
{
    public MyAttribute()
    {
        MessageBox.Show("MyAttribute ctor");
    } 
}
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

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

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


Sin*_*ian 6

我认为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");
    }
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*oud 4

让我们使用 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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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