托管事件的 C++ Cli 实现

C++ Cli implementation of managed event

我想在 cli/c++ 组件中实现一个托管接口。假设我的界面有这样的事件:

public interface IManagedInterface
{
   event EventHandler<ServiceCollectionChangedEventArgs> ServiceCollectionChanged;
}

我的 cli 组件存在 header 和 .cpp 文件。在我的 header 中,我定义了事件和引发它的私有方法。

ref class NativeImplementation : public IManagedInterface
{
  public:
     virtual event System::EventHandler<ServiceCollectionChangedEventArgs^>^ ServiceCollectionChanged;

  private:
    void RaiseServiceCollectionChanged(System::Type^ type, ChangeAction action);
};

在我的 .cpp 文件中,我想实现 raise 方法,这就是我苦苦挣扎的地方。

void NativeImplementation::RaiseServiceCollectionChanged(Type^ type, ChangeAction action)
      {
        EventHandler<ServiceCollectionChangedEventArgs^>^ local = NativeImplementation::ServiceCollectionChanged;
        if (local != nullptr) {
          local(this, gcnew ServiceCollectionChangedEventArgs(type, action));
        }
      }
}

我习惯在引发事件之前进行上述检查,但编译器抱怨 "error invalid use of event member"。谁能帮我?我什至需要在 C++ 中进行这些检查吗?

谢谢

在 C# 中,引发事件的习惯用法是将事件复制到局部变量,检查它是否为 null,然后使用局部变量调用处理程序,而不是从事件对象中重新读取。

// C# Idiom
void RaiseEvent()
{
    EventHandler<Whatever> handler = this.MyEvent;
    if (handler != null)
        handler(this, new Whatever());
}

您显然试图在 C++/CLI 中遵循相同的模式,但这不是必需的。当您访问 class 的 event 成员时,它会为您执行该惯用语。您需要做的就是像函数一样调用事件,它会正确完成。

// C++/CLI *only*. This will cause bugs if you do this in C#.
void NativeImplementation::RaiseServiceCollectionChanged(Type^ type, ChangeAction action)
{
    this->ServiceCollectionChanged(this, gcnew ServiceCollectionChangedEventArgs(type, action));
}

在底层,C# 为每个事件成员定义了两个方法:addremove,它们在使用 +=-= 时调用。上面的习惯用法是必要的,因为没有内置的空检查,并且需要本地副本以防事件在空检查和实际触发事件之间的另一个线程上被修改。 C++/CLI定义了三个方法:addremoveraise,其中raise方法实现了null检查和本地拷贝,和C#一样要求每个开发者自己实施。

你的事件是一个实例成员而不是静态成员,所以你应该在你的 raise 方法中使用 this 关键字来限定你的事件名称的范围(或者根本不限定它)。

EventHandler<ServiceCollectionChangedEventArgs^>^ local = this->ServiceCollectionChanged;