为什么在EventSource的子类上实现接口会在运行时抛出异常?

时间:2013-04-30 13:48:29

标签: .net-4.5 etw etw-eventsource perfview

我正在尝试通过.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

5 个答案:

答案 0 :(得分:12)

在提问时,@ LarsSkovslund的回答是正确的。但是,对于Microsoft.Diagnostics.Tracing.EventSource的稳定版本,Microsoft changed this according to their blog post

  

通过RTM版本,我们放宽了一些事件源验证   规则以启用某些高级使用方案。

     

这方面的两个变化:

     
      
  • EventSource类型现在可以实现接口,以便在使用接口的高级日志记录系统中使用事件源类型   定义一个共同的记录目标。

  •   
  • 引入了实用程序事件源类型的概念(定义为派生自EventSource的抽象类)以支持共享代码   跨项目中的多个事件源类型(例如,用于优化   WriteEvent()重载)。

  •   

系统。随.NET Framework提供的.Diagnostics.Tracing.EventSource支持.NET 4.6以上的这些方案

答案 1 :(得分:5)

虽然你不能让事件源实现一个接口,但是可以用另一个类包装它。 (这是Adapter design pattern

的一个实例
public class EventSourceAdapter : IEventSource
{
    private MyEventSource log;

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

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

答案 2 :(得分:4)

当EventSource类基于反射构建其事件结构时,它将仅考虑直接方法,例如在您的情况下,使用IMyEventSource不会考虑继承的成员。

您正在获取IndexOutOfRangeException,因为WriteEvent将使用event id参数来查找索引与事件id匹配的描述符块,从而在index不存在时抛出异常。

因此,简而言之,DONT使用接口来使用EventSource定义您的ETW事件。

干杯   拉斯

答案 3 :(得分:1)

截至今天(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

答案 4 :(得分:0)

这个问题有一个解决方法(抱歉,我不知道如何解释这个问题)。 如果你的方法是用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);
    }
}