2013-04-13 11 views
9

Jemand fragte mich eine Frage, wie wirC# Attribut über Haupt

line no 1 
line no 2 
line no 3 

Ohne eine Hauptmethode zu ändern, der liest

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

nun ein Ansatz mehrere Einstiegspunkte für die haben war drucken Konsolenanwendung. Allerdings habe ich versucht, einen anderen Ansatz, der wie folgt lautet:

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

Wenn ich einen Haltepunkt an jedem der Console.WriteLine gelten, ich bin in der Lage zu sehen, dass der Ansatz funktioniert jedoch nicht das gleiche auf das reflektierte Konsole.

Nur neugierig.

+1

'Ohne eine Hauptmethode zu ändern, die liest' ... wirklich?!? –

+2

@MichaelPerrenoud: Ich bin mir ziemlich sicher, dass dies eine Übung ist, die etwas cleveres Denken braucht. Ich denke wirklich, dass es ziemlich interessant ist. –

+0

@ArnoSluismans, das ist in Ordnung. Und es ist wirklich einfach, es war einfach wirklich komisch. Aber danke, dass du mich auf den richtigen Weg gebracht hast, schau dir meine Antwort an. –

Antwort

4

Lassen Sie uns AOP verwenden, und nutzen wir PostSharp. Sie müssen download and install it first, und dann müssen Sie einen Verweis darauf hinzufügen, mit NuGet. Sie müssen es installieren, weil es ein Haken in den Compiler ist. Wenn Sie Ihren Code kompilieren, injiziert PostSharp IL basierend auf den von Ihnen verwendeten Hooks in die Ausgabe.

Sobald Sie diese beiden Dinge getan haben eine neue Klasse für die AOP-Attribut hinzufügen:

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

und ändern Sie Ihre Main Methode wie folgt:

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

Sie sind Problem sein kann Aufgegliedert in die Suche nach den Hooks, die vor und nach Main Methodenausführung der Konsolenanwendung ausgelöst werden.

  • erster Haken ist ein Program statischer Konstruktor, die guarantee ist vorMain Methode in Program Klasse auszuführen.

  • Zweitens ist ein Ereignis ProcessExit ein AppDomain, die „Tritt ein, wenn die übergeordneten Prozess beendet der Standardanwendungsdomäne“. Sie können den statischen Konstruktor verwenden, um dieses Ereignis zu abonnieren.


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

druckt:

line no 1 
line no 2 
line no 3 

Nächster Teil wäre ein ziemlich lang. Ich werde versuchen, zu erklären, was das Problem mit SomeAttribute in Ihrer Frage ist.

Betrachten Sie zuerst diese StackOverflow-Frage genau when custom attributes constructors are executed. Dies ist nicht so einfach, wie es auf den ersten Blick scheinen mag.

Wie wir bereits wissen, wird ctor des benutzerdefinierten Attributs nur ausgeführt, wenn Sie über Reflektion darauf zugreifen. In Ihrem Beispiel löst die einfache Programmausführung keinen Attributkonstruktor aus.Aber warum trifft Ihr Breakpoint, wenn Sie die Methode SomeAttribute auf Main anwenden? Es stellt sich heraus, dass Visual Studio Reflexionen verwendet, um die Hauptmethode herauszufinden und einen Debugger an Ihre Anwendung anzuhängen. Aber an diesem Punkt gibt es kein Konsolenfenster. So ist die Aussage nutzlos und produziert zu wirken. Darüber hinaus scheint es alle folgenden Anweisungen für die Konsolenausgabe zu blockieren.

So wird im nächsten Code zu unterschiedlichen Ergebnissen führen, je nachdem, ob Sie es mit VS-Debugger ausführen oder nicht:

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

    } 
} 

class MyAttribute : Attribute 
{ 
    public MyAttribute() 
    { 
     MessageBox.Show("MyAttribute ctor"); 
    } 
} 

Wenn Sie es ohne Debugger (Ctrl + F5 in VS Standardkonfiguration) laufen, Sie werden sehen, dass das Programm beendet wird und keine Fenster erscheinen. Wenn Sie es mit Debugger ausführen (F5) Sie werden sehen,

enter image description here

und kein Konsolenfenster neben VS, nur Formen Symbol gewinnen: enter image description here

Wie ich bereits beschrieben habe, Wenn Sie versuchen, in die Konsole zu schreiben, wenn niemand da ist, haben alle anderen Aufrufe von keinen Einfluss auf Ihre Konsolenanwendung. Aus diesem Grund können Sie alle Konsolennachrichten anzeigen, auch wenn Sie im Konstruktor einen Haltepunkt setzen.

+1

+1 für eine andere clevere Lösung! –

+0

+1 für die Antwort, aber ich habe versucht herauszufinden, warum meine Lösung nicht funktioniert hat. – user2277247

+0

@ user2277247 Ich habe meine Antwort mit Erklärungen zu Ihrem beobachteten Verhalten –

6

Ich denke, Ilya Ivanov's answer ist möglicherweise der beste. Aber betrachten Sie meine als eine lustige Antwort auch:

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

+1 für das Denken aus der Box. Es besteht keine Notwendigkeit, die "Main" -Methode auszuführen, eine schöne Ecke in der Problembeschreibung. –

Verwandte Themen