2013-04-30 11 views
7

Sto cercando di utilizzare Event Tracing for Windows (ETW) nella mia applicazione .NET tramite la classe EventSource inclusa in .NET 4.5. Sto sottoclasse EventSource come MyEventSource e cercando di implementare un'interfaccia IMyEventSource (a scopo di scherno) come segue:Perché l'implementazione di un'interfaccia in una sottoclasse di EventSource genera un'eccezione in fase di runtime?

public interface IMyEventSource 
{ 
    void Test(); 
} 

public class MyEventSource : EventSource, IMyEventSource 
{ 
    public static MyEventSource Log = new MyEventSource(); 

    [Event(1)] 
    public void Test() 
    { 
    this.WriteEvent(1); 
    } 
} 

Quando eseguo PerfView ed eseguire questo codice, ottengo una IndexOutOfRangeException sulla chiamata a WriteEvent. Se rimuovo l'interfaccia modificando il codice ...

public class MyEventSource : EventSource 
{ 
    public static MyEventSource Log = new MyEventSource(); 

    [Event(1)] 
    public void Test() 
    { 
    this.WriteEvent(1); 
    } 
} 

... quindi tutto funziona perfettamente.

Ecco il codice che ho usato per la prova in entrambi i casi:

static void Main(string[] args) 
{ 
    MyEventSource.Log.Test(); 
} 

Perché il mio sottoclasse di EventSource pausa, se si implementa una semplice interfaccia?

Questo è un related post.

risposta

10

Al momento di chiedere la domanda, la risposta da @LarsSkovslund era corretta. Tuttavia, con la versione stabile di Microsoft.Diagnostics.Tracing.EventSource (non il sistema .Diagnostics.Tracing.EventSource whih è buildin al .Net Framework dalla versione 4.5), Microsoft changed this according to their blog post:

Con il rilascio RTM che abbiamo ha allentato alcune delle regole di convalida della sorgente di eventi per abilitare determinati scenari di utilizzo avanzati.

Le due modifiche in questa zona

  • tipi EventSource possono ora implementare le interfacce per consentire l'uso di tipi di origine evento a sistemi di registrazione avanzati che utilizzano interfacce per definire un target di registrazione comune.

  • Il concetto di un tipo di utilità origine evento (definito come una classe derivante estratto EventSource) viene introdotto per sostenere la condivisione di codice su più tipi di origine evento in un progetto (ad esempio per ottimizzare WriteEvent() sovraccarichi).

+3

È importante notare che questo è vero solo per la versione NuGet di EventsSource (ad esempio ** Microsoft **. Diagnostics.Tracing.EventSource). La versione integrata fornita con .NET 4.5 (cioè ** Sistema **. Diagnostics.Tracing.EventSource) ha ancora questa limitazione. –

+0

Parlo della versione di NuGet (Microsoft), non della versione di sistema. – magicandre1981

+0

Sì, lo so, ma potrebbe non essere evidente a chiunque legga questa risposta. –

4

Quando la classe EventSource sta costruendo la sua struttura di eventi in base alla riflessione, considererà solo i metodi diretti, ad es. i membri ereditati non sono considerati come nel tuo caso con l'uso di IMyEventSource.

Si sta ottenendo IndexOutOfRangeException perché WriteEvent utilizzerà il parametro ID evento per cercare un blocco descrittore con un indice che corrisponda all'ID evento generando così l'eccezione quando l'indice non esiste.

Quindi, in breve, DONT ha utilizzato le interfacce per definire gli eventi ETW utilizzando EventSource.

Acclamazioni Lars

+0

Grazie per la vostra risposta Lars. Fa apparire un paio di domande ... 1. Perché questo continua a essere rotto se si specificano esplicitamente gli ID evento (aggiunti all'esempio di codice sopra)? 2. Qualche raccomandazione su come prendere in giro una EventSource? Voglio i miei test di unità per verificare che un determinato evento venga attivato a determinate condizioni. – Mike

+0

Ciao Mike, 1) Dichiarare esplicitamente che l'id dell'evento non è di aiuto in quanto l'implementazione sottostante utilizza il reflection per ottenere metodi che utilizzano BindingFlags.DeclaredOnly (MSDN: "Specifica che devono essere considerati solo i membri dichiarati a livello della gerarchia del tipo fornito I membri ereditati non sono considerati. ") 2) L'unico modo che vedo è attraverso la delega ad es. implementare l'interfaccia esplicitamente 'IMyEventSource.Test()' e quindi chiamare 'Test()' da lì. –

+1

@Mike la versione stabile di EventSource ora consente l'interfaccia: http://blogs.msdn.com/b/dotnet/archive/2014/01/30/microsoft-diagnostics-tracing-eventsource-rtms.aspx?Redirected=true " I tipi EventSource possono ora implementare interfacce per abilitare l'uso dei tipi di origine degli eventi nei sistemi di registrazione avanzati che utilizzano le interfacce per definire un obiettivo di registrazione comune. " – magicandre1981

4

Anche se non si può avere l'origine evento implementare un'interfaccia, è possibile avvolgere con un'altra classe che fa. (Questo è un esempio del Adapter design pattern)

public class EventSourceAdapter : IEventSource 
{ 
    private MyEventSource log; 

    public EventSourceAdapter(MyEventSource log) 
    { 
     this.log = log; 
    } 

    public void Test() 
    { 
     log.Test() 
    } 
} 
} 
1

A partire da oggi (29 settembre 2014), il codice il manifesto originale fornito non funziona con il codice nativo che viene fornito con .NET 4.5. Genera ancora un'eccezione "IndexOutOfRange" e, come dice, lo fa solo se gli eventi ETW vengono monitorati (sto usando PerfView).

Detto questo, ho verificato con .NET versione 4.0 utilizzando la libreria EventSource di Microsoft da nuget.org e il suo codice funziona con quello.

I successivo installato Microsoft EventSource Library da nuget in un progetto .NET versione 4.5. Mi sono assicurato di ereditare da Microsoft.Diagnostics.Tracing.EventSource e non da System.Diagnostics.Tracing.EventSource dalla libreria nativa .NET 4.5. Questo ha funzionato, ma ho anche scoperto che dovevo contrassegnare quei metodi ereditati dall'interfaccia con l'attributo [Microsoft.Diagnostics.Tracing.Event (int)].

Ho anche osservato alcuni comportamenti strani che non sono riuscito a spiegare. Talvolta alcuni dei miei eventi vengono visualizzati in PerfView con il nome "EventID (0)" anziché il nome del metodo. A volte ho ottenuto eccezioni IndexOutOfRange inaspettate. Come meglio posso dire che la registrazione di una precedente prova è rimasta in memoria. Ho iniziato a rinominare la mia classe EventSource tra le prove, e non avevo più questi problemi.

JR

+0

Otterrete maggiore attenzione se ponete la vostra domanda in una nuova domanda invece di inserirla come risposta. –

+1

Grazie, ma non sono davvero interessato agli strani comportamenti che ho trovato. Volevo aggiungere la mia risposta a questa domanda perché pensavo che le risposte fornite non coprissero completamente come utilizzare le interfacce con le classi EventSource e volevo assicurarmi che qualcun altro con un problema simile potesse beneficiare della mia esperienza. Se inserissi una nuova domanda, sarebbe la stessa domanda e quindi ridondante. – jrv

0

C'è una soluzione per questo problema (mi dispiace non so come spiegare il problema). Se il metodo è decorato con lo NonEventAttribute, sarà possibile utilizzare la propria interfaccia.

L'interfaccia:

public interface IMyEventSource 
{ 
    void Test(); 
} 

e l'implementazione:

public class MyEventSource : EventSource, IMyEventSource 
{ 
    public static MyEventSource Log = new MyEventSource(); 

    [NonEvent] 
    public void Test() 
    { 
     this.InternalTest(); 
    } 

    [Event(1)] 
    private void InternalTest() 
    { 
     this.WriteEvent(1); 
    } 
} 
Problemi correlati