c# attribute over main

后端 未结 3 1128
被撕碎了的回忆
被撕碎了的回忆 2021-01-02 08:29

Someone asked me a question as to how we can print

line no 1
line no 2
line no 3

Without changing a main method which reads



        
相关标签:
3条回答
  • 2021-01-02 09:17

    Let's use AOP, and let's leverage PostSharp. You're going to need to download and install it first, and then after that you'll need to add a reference to it using NuGet. You have to install it because it's a hook into the compiler. See, when you compile your code, PostSharp actually injects IL into the output based on the hooks you use.

    Once you've done those two things add a new class for the AOP attribute:

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

    and then modify your Main method like this:

    [ConsoleAspect]
    static void Main(string[] args)
    {
        Console.WriteLine("line no 2");
    }
    
    0 讨论(0)
  • 2021-01-02 09:32

    I think Ilya Ivanov's answer is possibly the best one. However consider mine as a funny answer too:

    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");
        }
    }
    
    0 讨论(0)
  • 2021-01-02 09:33

    You're problem can be broken down into the search of the hooks, which are triggered before and after Main method execution of the console application.

    • First hook is a Program static constructor, which is guarantee to execute before Main method in Program class.

    • Second is an event ProcessExit of a AppDomain, which "Occurs when the default application domain's parent process exits". You can use static constructor to subscribe to this event.


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

    prints:

    line no 1
    line no 2
    line no 3
    

    Next part would be quite a long one. I'll try to explain what is the problem with SomeAttribute in your question.

    First of all, consider this StackOverflow question to know exactly when custom attributes constructors are executed. This isn't so simple, as it might seem at first glance.

    As we already know, ctor of custom attribute will only be executed, when you will access it via reflection. So in you example simple program execution won't trigger attribute constructor. But why do your breakpoint hit, when you apply SomeAttribute to Main method? It turns out, that visual studio uses reflexion to find out main method and attach a debugger to your application. But there is no console window at that point. So statement Console.WriteLine is useless and produce to effect. Moreover, it seems to block all next statements to console output.

    So next code will produce different results, depending if you run it with VS debugger or not:

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

    If you run it without debugger (Ctrl + F5 in VS default configuration), you'll see, that program terminates and no windows appear. When you execute it with debugger (F5) you'll see

    enter image description here

    and no console window next to VS, only win forms icon: enter image description here

    As I've described earlier, when you try to write to console when there is no one, then all other calls to Console.WriteLine doesn't affect your console application. That's why you can see any console messages, even if you step a breakpoint in the constructor.

    0 讨论(0)
提交回复
热议问题