c#属性高于main

Posted

技术标签:

【中文标题】c#属性高于main【英文标题】:c# attribute over main 【发布时间】:2013-04-13 10:53:46 【问题描述】:

有人问我如何打印

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 上应用断点时,我可以看到该方法有效,但是在控制台上没有反映出来。

只是好奇。

【问题讨论】:

Without changing a main method which reads ...真的吗?!? @MichaelPerrenoud:我很确定这是一个需要一些聪明思考的练习。事实上,我真的认为这很有趣。 @ArnoSluismans,没关系。这真的很简单,真的很奇怪。但是感谢您引导我走上正确的道路,看看我的回答。 下面的解决方案都很有帮助,但我很好奇为什么尽管命中了断点,正如预期的那样,属性技术不起作用。 【参考方案1】:

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

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

Second 是 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 的问题。

首先,考虑这个 *** 问题以准确了解when custom attributes constructors are executed。这并不像乍一看那么简单。

我们已经知道,自定义属性的 ctor 只会在您通过反射访问它时执行。因此,在您的示例中,简单的程序执行不会触发属性构造函数。但是,当您将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) 执行它时,您会看到

VS旁边没有控制台窗口,只有win表单图标:

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

【讨论】:

+1 为答案,但我试图弄清楚为什么我的解决方案不起作用。 @user2277247 我更新了我的答案,解释了你观察到的行为【参考方案2】:

我认为Ilya Ivanov's answer 可能是最好的。但是,我的答案也很有趣:

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

【讨论】:

+1 开箱即用。无需执行Main 方法,问题陈述中的漂亮角落案例。【参考方案3】:

让我们使用 AOP,并利用 PostSharp。您将需要download and install it first,然后您需要使用 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");

【讨论】:

以上是关于c#属性高于main的主要内容,如果未能解决你的问题,请参考以下文章

c# 属性改变

为啥获取私有属性一无所获? (c#) [关闭]

在c#中怎么能在一个窗口中设置另一个窗口控件的属性?急急急!!!

C#提示不只定义了一个入口点,请使用/main进行编译以指定包含入口点的类型

C#中简单的继承和多态

C#使用winform的控件记录