2013-04-30 23 views
7

Próbuję użyć Event Tracing for Windows (ETW) w mojej aplikacji .NET za pośrednictwem klasy EventSource, która została uwzględniona w .NET 4.5. Ja instacji EventSource jak MyEventSource i próbuje implementować interfejs IMyEventSource (dla celów drwiących) w następujący sposób:Dlaczego implementacja interfejsu na podklasę EventSource rzuca wyjątek w czasie wykonywania?

public interface IMyEventSource 
{ 
    void Test(); 
} 

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

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

Kiedy biegnę PerfView i wykonanie tego kodu, otrzymuję IndexOutOfRangeException na wezwanie do WriteEvent. Jeśli usunę interfejs, modyfikując kod ...

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

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

... wtedy wszystko działa dobrze.

Oto kod użyłem do testów w obu przypadkach:

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

Dlaczego mój podklasa EventSource przerwy czy po prostu implementuje interfejs?

Oto related post.

Odpowiedz

10

W momencie zadać pytanie, odpowiedź z @LarsSkovslund była prawidłowa. Jednak ze stabilnej wersji Microsoft.Diagnostics.Tracing.EventSource (nieSystemu .Diagnostics.Tracing.EventSource whih jest buildin do .Net Framework od wersji 4.5), Microsoft changed this according to their blog post:

Wraz z wydaniem RTM mamy zwolnił niektóre z metod sprawdzania poprawności źródeł zdarzeń reguł w celu włączenia pewnych zaawansowanych scenariuszy użycia.

Dwie zmiany w tej dziedzinie:

  • rodzaje EventSource może teraz implementują interfejsy w celu umożliwienia korzystania z typów źródeł wydarzeniem w zaawansowanych systemów rejestrowania, które wykorzystują interfejsy określić wspólny cel rejestrowania.

  • Pojęcie typu źródło zdarzenia narzędzie (określaną jako klasy abstrakcyjnej wynikającego z EventSource) wprowadza się do wspierania kod podziału w wielu rodzajów źródeł zdarzeń w projekcie (na przykład w celu optymalizacji WriteEvent() Przeciążenia).

+3

Należy zauważyć, że dotyczy to tylko wersji NuSet zdarzenia EventsSource (tj. ** Microsoft **. Diagnostics.Tracing.EventSource). Wbudowana wersja dostarczana z .NET 4.5 (tj. ** System **. Diagnostics.Tracing.EventSource) nadal ma to ograniczenie. –

+0

Mówię o wersji NuGet (Microsoft), a nie wersji System. – magicandre1981

+0

Tak, wiem, ale to może nie być oczywiste dla nikogo czytającego tę odpowiedź. –

4

Gdy klasa EventSource buduje swoją strukturę zdarzeń na podstawie refleksji, uwzględni tylko metody bezpośrednie. odziedziczeni członkowie nie są traktowani jak w twoim przypadku przy użyciu IMyEventSource.

Otrzymujesz IndexOutOfRangeException, ponieważ WriteEvent będzie używał parametru id zdarzenia do przeszukiwania bloku deskryptora z indeksem pasującym do identyfikatora zdarzenia, rzucając w ten sposób wyjątek, gdy indeks nie istnieje.

Krótko mówiąc, wykorzystano interfejsy DONT do zdefiniowania zdarzeń ETW przy użyciu EventSource.

Cheers Lars

+0

Dziękuję za odpowiedź Lars. Pojawia się kilka pytań ... 1. Dlaczego to się nie udaje, jeśli wyraźnie określam identyfikatory zdarzeń (dodane do powyższego przykładu kodu)? 2. Wszelkie zalecenia dotyczące sposobu na kpiny z EventSource? Chcę, aby moje testy jednostkowe potwierdziły, że określone zdarzenie jest uruchamiane pod pewnymi warunkami. – Mike

+0

Witaj Mike, 1) Jawnie deklarowanie identyfikatora zdarzenia nie pomoże, ponieważ podstawowa implementacja używa odbicia, aby uzyskać metody przy użyciu BindingFlags.DeclaredOnly (MSDN: "Określa, że ​​tylko członkowie deklarowani na poziomie hierarchii dostarczonego typu powinni być uważani za Dziedziczeni członkowie nie są brani pod uwagę. ") 2) Jedyny sposób, jaki widzę to poprzez delegację, np. implementuj jawnie interfejs 'IMyEventSource.Test()', a następnie wywołaj 'Test()'. –

+1

@Mike stabilna wersja EventSource umożliwia teraz interfejs: http://blogs.msdn.com/b/dotnet/archive/2014/01/30/microsoft-diagnostics-tracing-eventsource-rtms.aspx?Redirected=true " Typy EventSource mogą teraz implementować interfejsy, aby umożliwić korzystanie z typów źródeł zdarzeń w zaawansowanych systemach rejestrowania, które wykorzystują interfejsy do zdefiniowania wspólnego celu rejestrowania. " – magicandre1981

4

Choć nie można mieć źródło wydarzenie implementować interfejs, możliwe jest, aby owinąć go z innej klasy, dokłada. (Jest to instancja Adapter design pattern)

public class EventSourceAdapter : IEventSource 
{ 
    private MyEventSource log; 

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

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

dzień dzisiejszy (29 września 2014), kod oryginalny plakat pod warunkiem nie działa z natywnym kodzie, że statki z .NET 4.5. Nadal generuje wyjątek "IndexOutOfRange" i, jak mówi, robi to tylko wtedy, gdy zdarzenia ETW są monitorowane (używam PerfView).

Powiedziałem, że sprawdziłem z .NET w wersji 4.0 przy użyciu biblioteki Microsoft EventSource Library z nuget.org, a jego kod działa z tym.

Następnie zainstalowałem bibliotekę Microsoft EventSource Library z nuget w projekcie .NET w wersji 4.5. Upewniłem się, że dziedziczę z Microsoft.Diagnostics.Tracing.EventSource, a nie z System.Diagnostics.Tracing.EventSource z natywnej biblioteki .NET 4.5. To zadziałało, ale odkryłem również, że musiałem zaznaczyć te metody, które odziedziczyły po interfejsie z atrybutem [Microsoft.Diagnostics.Tracing.Event (int)].

Obserwowałem także dziwne zachowania, których nie potrafiłem wyjaśnić. Czasami niektóre z moich zdarzeń pojawiają się w PerfView jako o nazwie "EventID (0)" zamiast nazwy metody. Czasami wystąpiły nieoczekiwane wyjątki IndexOutOfRange. Jak najlepiej mogę się domyślić, rejestracja z poprzedniego badania pozostała w pamięci. Zacząłem zmieniać nazwę mojej klasy EventSource między próbami i nie miałem już takich problemów.

JR

+0

Zyskasz więcej uwagi, jeśli zadasz pytanie w nowym pytaniu, zamiast umieszczać je w odpowiedzi. –

+1

Dzięki, ale nie jestem zainteresowany dziwnymi zachowaniami, które znalazłem. Chciałem dodać moją odpowiedź na to pytanie, ponieważ uważałem, że podane odpowiedzi nie w pełni opisują sposób korzystania z interfejsów z klasami EventSource i chciałem upewnić się, że ktoś z podobnym problemem może skorzystać z mojego doświadczenia. Gdybym postawił to na nowe pytanie, byłoby to to samo pytanie i tak zbędne. – jrv

0

Istnieje obejście tego problemu (sorry nie wiem jak to wytłumaczyć problem). Jeśli jesteś metodą jest ozdobiony NonEventAttribute będziesz mógł korzystać z interfejsu.

interfejsu:

public interface IMyEventSource 
{ 
    void Test(); 
} 

i wdrożenie:

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