嵌入式 Mono:如何在 C++ 中引发事件?

发布于 2024-12-29 21:59:42 字数 647 浏览 0 评论 0原文

我正在开发一个嵌入 Mono 的应用程序,我想将一个事件从 C++ 层引发到 C# 层。这就是我所拥有的:

 void* itr(NULL);
 MonoEvent* monoEvent;
 while(monoEvent= mono_class_get_events(klass, &itr))
 {
     if(0 == strcmp(eventName, mono_event_get_name(monoEvent)))
         raiseMethod = mono_event_get_raise_method(monoEvent);
 }

但是,raiseMethod 总是返回为 NULL。查看 MonoEvent 的结构,看起来添加和删除方法已填充,但没有填充?我需要做一些特别的事情才能让它发挥作用吗?

编辑:如果重要的话,这是我在 C# 层中使用的委托、类和事件的(基本)形式。

public delegate void MyHandler(uint id);
public class SimpleComponent : NativeComponent
{
    public event MyHandler OnEnter;
    public event MyHandler OnExit;
}

I'm working on an application that's embedding Mono, and I'd like to raise an event from the C++ layer into the C# layer. Here's what I have:

 void* itr(NULL);
 MonoEvent* monoEvent;
 while(monoEvent= mono_class_get_events(klass, &itr))
 {
     if(0 == strcmp(eventName, mono_event_get_name(monoEvent)))
         raiseMethod = mono_event_get_raise_method(monoEvent);
 }

However, raiseMethod always comes back as NULL. Looking at the structure of the MonoEvent, it looks like the add and remove methods were populated, but not the raise? Is there something special I have to do to get this to work?

EDIT: If it matters, here's the (basic) form of the delegate, class, and events I'm using in the C# layer.

public delegate void MyHandler(uint id);
public class SimpleComponent : NativeComponent
{
    public event MyHandler OnEnter;
    public event MyHandler OnExit;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

靑春怀旧 2025-01-05 21:59:42

事件可以在父类中定义吗?如果是这样,您需要使用如下内容向上遍历类层次结构:

MonoEvent* monoEvent;
while (klass)
{
    void* itr = NULL;
    while(monoEvent= mono_class_get_events(klass, &itr))
    {
       if(0 == strcmp(eventName, mono_event_get_name(monoEvent)))
         raiseMethod = mono_event_get_raise_method(monoEvent);
   }
   klass = mono_class_get_parent(klass);
}

在注释和重新阅读问题后进行编辑

事件的 raise 方法为 NULL 是正常的。

对于使用 C# event 关键字或 Visual Basic Event 关键字声明的事件,此方法通常返回 null。这是因为 C# 和 Visual Basic 编译器默认不生成这样的方法。

来源

恐怕很难触发事件一个类的。因为它实际上打破了 .NET 中事件的概念 - 类本身只能触发自己的事件。实际上,即使从 C# 中也很难引发其他类的事件。

从概念上讲,事件是一对 add_handler 和 remove_handler 方法,您可以在其中指定事件情况发生时要调用的委托。如何实现事件取决于类。从技术上讲,这只是一个私人委托领域,AFAIK。
您可以尝试找到它。

我不确定这是否是正确的方法,但如何通过 .NET/C# 中的反射引发事件?< 中的答案之一/a> 描述如何使用反射引发事件。您可能会尝试将其转换为 mono_class / mono_field 调用等。

May the event be defined in parent class? If so you need to traverse up the class hierarchy with something like the following:

MonoEvent* monoEvent;
while (klass)
{
    void* itr = NULL;
    while(monoEvent= mono_class_get_events(klass, &itr))
    {
       if(0 == strcmp(eventName, mono_event_get_name(monoEvent)))
         raiseMethod = mono_event_get_raise_method(monoEvent);
   }
   klass = mono_class_get_parent(klass);
}

EDIT after comment and re-reading question:

It is normal that the raise method for event is NULL.

This method usually returns null for events declared with the C# event keyword or the Visual Basic Event keyword. This is because the C# and Visual Basic compilers do not generate such a method by default.

(source)

I am afraid it may be hard to fire an event of a class. Because it is actually breaking the concept of events in .NET - which says that the class itself can only fire its own Event. Actually, even from C# it is hard to raise the event of other class.

Conceptually, events are pair of add_handler and remove_handler methods where you specify delegates to be called when event's circumstances occur. It is up to class how it implements events. Technically, it is just a private delegate field, AFAIK.
You may try to locate it.

I am not sure if it is a proper approach, but one of the answers in How do I raise an event via reflection in .NET/C#? describes how to raise event using reflection. You might attempt to convert it into mono_class / mono_field calls, etc.

蹲墙角沉默 2025-01-05 21:59:42

克里兹的回答是最完整的。这就是我修复代码以使其按照我“期望”的方式工作的方法。

我将 C# 端更改为:

public delegate void MyHandler(uint aEntityId);
public class SimpleComponent: NativeComponent
{
    public event MyHandler OnEnter;
    public event MyHandler OnExit;

    protected void CallOnEnter(uint aEntityId)
    {
        if (OnEnter != null)
            OnEnter(aEntityId);
    }

    protected void CallOnExit(uint aEntityId)
    {
        if (OnExit!= null)
            OnExit(aEntityId);
    }
}

然后使用 mono 方法

raiseMethod = mono_class_get_method_from_name(klass, "CallOnEnter", 1);

Krizz's answer is the most complete. This is how I fixed my code to work how I would "expect".

I changed the C# side to:

public delegate void MyHandler(uint aEntityId);
public class SimpleComponent: NativeComponent
{
    public event MyHandler OnEnter;
    public event MyHandler OnExit;

    protected void CallOnEnter(uint aEntityId)
    {
        if (OnEnter != null)
            OnEnter(aEntityId);
    }

    protected void CallOnExit(uint aEntityId)
    {
        if (OnExit!= null)
            OnExit(aEntityId);
    }
}

Then grabbed the mono method with

raiseMethod = mono_class_get_method_from_name(klass, "CallOnEnter", 1);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文