问题
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
static void Main(string[] args)
{
Console.WriteLine("line no 2");
}
Now one approach was to have multiple entry points for the console application. However I tried another approach which goes as follows :
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");
}
}
When I apply a breakpoint on each of the WriteLine, I am able to see that the approach works, however, the same isn't reflected on the console.
Just curious.
回答1:
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 beforeMain
method inProgram
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
and no console window next to VS, only win forms icon:
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.
回答2:
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");
}
}
回答3:
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");
}
来源:https://stackoverflow.com/questions/15987026/c-sharp-attribute-over-main