2013-04-13 10 views
9

Qualcuno mi ha fatto una domanda su come possiamo stampareC# attributo nel corso principale

line no 1 
line no 2 
line no 3 

Senza cambiare un metodo principale che recita

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

Ora un approccio era quello di avere più punti di ingresso per la applicazione console. Tuttavia ho provato un altro approccio che va come segue:

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

Quando applico un punto di interruzione su ciascuna delle WriteLine, sono in grado di vedere che l'approccio funziona, tuttavia, lo stesso non si riflette sulla console.

Solo curioso.

+1

'Senza cambiare un metodo principale che legge' ... davvero?!? –

+2

@MichaelPerrenoud: Sono abbastanza sicuro che questo è un esercizio che dovrebbe prendere un pensiero intelligente. Onestamente penso che sia piuttosto interessante, infatti. –

+0

@ArnoSluismans, va bene. Ed è davvero semplice, è stato davvero strano. Ma grazie per avermi indirizzato sulla strada giusta, dare un'occhiata alla mia risposta. –

risposta

4

Utilizziamo AOP e sfruttiamo PostSharp. Avrai bisogno di download and install it first e poi dovrai aggiungere un riferimento ad esso usando NuGet. Devi installarlo perché è un gancio nel compilatore. Vedi, quando compili il tuo codice, PostSharp in realtà inietta IL nell'output in base agli hook che usi.

volta che avete fatto queste due cose aggiungere una nuova classe per l'attributo 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"); 
     } 
    } 
} 

e quindi modificare il metodo di Main in questo modo:

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

Non Sei problema può essere suddiviso nella ricerca dei ganci, che vengono attivati ​​prima e dopo l'esecuzione del metodo Main dell'applicazione console.

  • primo gancio è un costruttore statico Program, che è guarantee eseguire primaMain metodo Program classe.

  • In secondo luogo è un evento ProcessExit di un AppDomain, che "si verifica quando le uscite di processo genitore del dominio applicazione predefinita". È possibile utilizzare il costruttore statico per iscriversi a questo evento.


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

stampe:

line no 1 
line no 2 
line no 3 

parte successiva sarebbe abbastanza lunga. Proverò a spiegare qual è il problema con SomeAttribute nella tua domanda.

Prima di tutto, considera questa domanda StackOverflow per sapere esattamente when custom attributes constructors are executed. Non è così semplice, come potrebbe sembrare a prima vista.

Come già sappiamo, il certificato dell'attributo personalizzato verrà eseguito solo quando sarà possibile accedervi tramite riflessione. Quindi nell'esempio semplice esecuzione del programma non si innesca costruttore di attributi.Ma perché viene colpito il punto di interruzione quando si applica il metodo SomeAttribute a Main? Si scopre che lo studio visivo usa la riflessione per scoprire il metodo principale e allegare un debugger alla tua applicazione. Ma non c'è nessuna finestra della console in quel punto. Quindi l'affermazione Console.WriteLine è inutile e produce effetti. Inoltre, sembra bloccare tutte le prossime istruzioni sull'output della console.

Così la prossima codice produrrà risultati diversi, a seconda se lo si esegue con VS debugger o no:

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

    } 
} 

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

Se lo si esegue senza debugger (Ctrl + F5 nella configurazione di default VS), vedrai, quel programma termina e non appare nessuna finestra. Quando si esegue con il debugger (F5) vedrete

enter image description here

e nessuna finestra della console accanto al VS, vince solo forme icona: enter image description here

Come ho descritto in precedenza, quando si tenta di scrivere sulla console quando non c'è nessuno, tutte le altre chiamate a Console.WriteLine non influiscono sull'applicazione della console. Ecco perché è possibile visualizzare tutti i messaggi della console, anche se si esegue un punto di interruzione nel costruttore.

+1

+1 per un'altra soluzione intelligente! –

+0

+1 per la risposta, ma stavo cercando di capire perché la mia soluzione non ha funzionato. – user2277247

+0

@ user2277247 Ho aggiornato la mia risposta con le spiegazioni sul comportamento osservato –

6

Penso che il Ilya Ivanov's answer sia probabilmente il migliore. Tuttavia considera il mio come una risposta divertente anche:

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 per pensare fuori dagli schemi. Non c'è bisogno di eseguire il metodo 'Main', bel caso d'angolo all'interno di una dichiarazione di problemi. –