我试图通过.NET 4.5中包含的Event Tracing for Windows (ETW)类在我的.NET应用程序中使用EventSource。我将EventSource
子类化为MyEventSource
并尝试实现接口IMyEventSource
(用于模拟目的),如下所示:
public interface IMyEventSource
{
void Test();
}
public class MyEventSource : EventSource, IMyEventSource
{
public static MyEventSource Log = new MyEventSource();
[Event(1)]
public void Test()
{
this.WriteEvent(1);
}
}
当我运行PerfView并执行此代码时,我在调用IndexOutOfRangeException
时获得了WriteEvent
。如果我通过修改代码删除界面...
public class MyEventSource : EventSource
{
public static MyEventSource Log = new MyEventSource();
[Event(1)]
public void Test()
{
this.WriteEvent(1);
}
}
...然后一切正常。
以下是我在两种情况下用于测试的代码:
static void Main(string[] args)
{
MyEventSource.Log.Test();
}
为什么我的EventSource
子类会破坏它只是实现一个接口?
这是一个related post。
在提问时,@ LarsSkovslund的回答是正确的。然而,随着Microsoft.Diagnostics.Tracing.EventSource的稳定版本,Microsoft changed this according to their blog post:
通过RTM版本,我们放宽了一些事件源验证规则,以便启用某些高级使用方案。
这方面的两个变化:
- EventSource类型现在可以实现接口,以便在使用接口定义公共日志记录目标的高级日志记录系统中使用事件源类型。
- 引入了实用程序事件源类型(定义为派生自EventSource的抽象类)的概念,以支持跨项目中的多个事件源类型共享代码(例如,用于优化的WriteEvent()重载)。
随.NET Framework提供的System.Diagnostics.Tracing.EventSource支持.NET 4.6的这些方案
虽然你不能让事件源实现一个接口,但是可以用另一个类包装它。 (这是Adapter design pattern的一个例子)
public class EventSourceAdapter : IEventSource
{
private MyEventSource log;
public EventSourceAdapter(MyEventSource log)
{
this.log = log;
}
public void Test()
{
log.Test()
}
}
}
当EventSource类基于反射构建其事件结构时,它将仅考虑直接方法,例如在您的情况下,使用IMyEventSource不会考虑继承的成员。
您将获得IndexOutOfRangeException,因为WriteEvent将使用event id参数来查找具有与事件id匹配的索引的描述符块,从而在index不存在时抛出异常。
所以简而言之,DONT使用接口来使用EventSource定义您的ETW事件。
干杯拉尔斯
截至今天(2014年9月29日),原始海报提供的代码不适用于.NET 4.5附带的本机代码。它仍然会生成一个“IndexOutOfRange”异常,正如他所说,只有在监视ETW事件时才会这样做(我使用的是PerfView)。
也就是说,我使用来自nuget.org的Microsoft EventSource库检查了.NET 4.0版,他的代码确实可以使用它。
我接下来在.NET版本4.5项目中从nuget安装了Microsoft EventSource Library。我确保从Microsoft.Diagnostics.Tracing.EventSource继承而不是从本机.NET 4.5库中的System.Diagnostics.Tracing.EventSource继承。这有效,但我还发现我必须使用[Microsoft.Diagnostics.Tracing.Event(int)]属性标记从接口继承的那些方法。
我也观察到一些我无法解释的奇怪行为。有时我的一些事件在PerfView中显示为名为“EventID(0)”而不是方法名称。有时我得到意外的IndexOutOfRange异常。我可以猜测,之前的试验中的注册仍然在记忆中。我开始在试验之间重命名我的EventSource类,我不再遇到这些问题了。
JR
这个问题有一个解决方法(抱歉,我不知道如何解释这个问题)。如果你的方法是用NonEventAttribute
装饰的,你将能够使用你的界面。
你的界面:
public interface IMyEventSource
{
void Test();
}
并实施:
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);
}
}