c# 属性覆盖主函数

13 浏览
0 Comments

c# 属性覆盖主函数

有人问我一个问题,即如何在不改变读取的主方法的情况下打印以下内容:

第一行
第二行
第三行

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

class Program
{
    [Some]
    static void Main(string[] args)
    {
        Console.WriteLine("第二行");
    }
}
class SomeAttribute : Attribute
{
    public SomeAttribute()
    {
        Console.WriteLine("第一行");
    }
    ~SomeAttribute()
    {
        Console.WriteLine("第三行");
    }
}

当我在每个WriteLine上设置断点时,我发现这种方法是有效的,但是在控制台上却没有显示出来。

只是好奇。

0
0 Comments

问题出现的原因是使用了PostSharp库来实现AOP功能,但在主函数上应用特性时出现了错误。解决方法是引入PostSharp库,并创建一个AOP特性类,在特性类中重写OnEntry和OnExit方法,在主函数上应用该特性类。

首先,需要下载并安装PostSharp库,然后使用NuGet添加对PostSharp库的引用。这是因为PostSharp库是编译器的一个钩子,当编译代码时,它会根据使用的钩子将IL代码注入到输出中。

接下来,创建一个AOP特性类,代码如下:

using PostSharp.Aspects;
using System;
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");
        }
    }
}

然后,在主函数上应用该特性类,代码如下:

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

通过以上操作,我们就可以在主函数中实现AOP功能,并在控制台输出相应的日志信息。

0
0 Comments

在上述代码中,我们看到一个名为`Program`的类,它包含了一个静态构造函数和一个`Main`方法。静态构造函数在类的第一次被使用之前被调用,并且只会执行一次。在这个例子中,静态构造函数中的代码会在程序运行之前被执行。

静态构造函数中的代码输出了三行文本,并且在最后一行代码中调用了`Environment.Exit(0)`。这个方法会立即终止程序的执行。

然而,在`Main`方法中,我们只输出了一行文本。这就是问题所在:由于静态构造函数在`Main`方法之前被执行,并且在其中调用了`Environment.Exit(0)`,所以`Main`方法中的代码根本没有机会被执行。

解决这个问题的方法是将`Environment.Exit(0)`的调用从静态构造函数中移除,或者将其放在一个条件语句中,以便只在特定条件下执行。

以下是修复后的代码示例:

public class Program
{
    static Program()
    {
        Console.WriteLine("line no 1");
        Console.WriteLine("line no 2");
        Console.WriteLine("line no 3");
    }
    static void Main(string[] args)
    {
        if (!Environment.GetCommandLineArgs().Contains("/exit"))
        {
            Console.WriteLine("line no 2");
        }
    }
}

在修复后的代码中,我们将`Environment.Exit(0)`的调用移除,并在`Main`方法中添加了一个条件语句。这个条件语句检查命令行参数,如果参数中不包含`/exit`,则输出"line no 2"。这样,我们就能够在不终止程序执行的情况下输出所需的文本。

通过这种修复,我们可以确保在`Main`方法中的代码得到执行,而不会被静态构造函数中的代码所阻止。

0
0 Comments

问题出现的原因是在执行控制台应用程序的Main方法之前和之后触发的钩子的搜索问题。

  • 第一个钩子是Program静态构造函数,在Program类中的Main方法之前执行。
  • 第二个是AppDomain的事件ProcessExit,它在“默认应用程序域的父进程退出时发生”。您可以使用静态构造函数订阅此事件。

接下来的部分将会很长。我将尝试解释您问题中的SomeAttribute的问题所在。

首先,要了解确切的情况,可以参考这个StackOverflow问题,了解custom attributes构造函数何时执行。这并不像乍一看那么简单。

正如我们已经知道的那样,只有当您通过反射访问时,自定义属性的构造函数才会被执行。所以在您的示例中,简单的程序执行不会触发属性构造函数。但是为什么当您将SomeAttribute应用于Main方法时,断点却命中了呢?原来,Visual Studio使用反射来找到主方法并将调试器附加到您的应用程序上。但此时还没有控制台窗口。所以Console.WriteLine语句是无用的,也不会产生效果。此外,它似乎会阻塞所有后续的控制台输出语句。

因此,下面的代码将根据您是否使用VS调试器来产生不同的结果:

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

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

enter image description here

并且在VS旁边没有控制台窗口,只有窗体图标:

enter image description here

如前所述,当您尝试在没有控制台窗口的情况下写入控制台时,所有其他对Console.WriteLine的调用都不会影响您的控制台应用程序。这就是为什么即使在构造函数中设置断点,您也看不到任何控制台消息的原因。

对于这个答案给予+1,但我想弄清楚为什么我的解决方法不起作用。

我已更新我的答案,解释了您观察到的行为。

0