在 C++ 中触发事件并在 C# 中处理它们

Posted

技术标签:

【中文标题】在 C++ 中触发事件并在 C# 中处理它们【英文标题】:Firing events in C++ and handling them in C# 【发布时间】:2018-06-04 06:57:32 【问题描述】:

我有一台带有一些数字 I/O 引脚的工业计算机。制造商提供了一些 C++ 库和示例来处理引脚状态的变化。

我需要将此事件集成到 C# 应用程序中。 AFAIK 执行此操作的最简单方法是:

    为制造商库创建一个托管 C++/CLI 包装器,当 DIO 引脚发出中断时触发事件。 引用该包装器并处理 C# 部分中的事件,因为它们是正常的 C# 事件。

我试图用一些模拟对象来完成这项工作,但没有运气。从文档来看,在我的情况下,函数 EventHandler 应该完成大部分“肮脏的工作”。以下信息在旧线程和 MSDN 文档中的 EventHandler 示例中可用,我最终得到了这个测试代码:

C++/CLI

using namespace System;

public ref class ThresholdReachedEventArgs : public EventArgs

public:
    property int Threshold;
    property DateTime TimeReached;
;

public ref class CppCounter

private:
    int threshold;
    int total;

public:
    CppCounter() ;

    CppCounter(int passedThreshold)
    
        threshold = passedThreshold;
    

    void Add(int x)
    
        total += x;
        if (total >= threshold) 
            ThresholdReachedEventArgs^ args = gcnew ThresholdReachedEventArgs();
            args->Threshold = threshold;
            args->TimeReached = DateTime::Now;
            OnThresholdReached(args);
        
    

    event EventHandler<ThresholdReachedEventArgs^>^ ThresholdReached;

protected:
    virtual void OnThresholdReached(ThresholdReachedEventArgs^ e)
    
        ThresholdReached(this, e);
    
;

public ref class SampleHandler

public:
    static void c_ThresholdReached(Object^ sender, ThresholdReachedEventArgs^ e)
    
        Console::WriteLine("The threshold of 0 was reached at 1.",
            e->Threshold, e->TimeReached);
        Environment::Exit(0);
    
;

void main()

    return;
    CppCounter^ c = gcnew CppCounter(20);
    c->ThresholdReached += gcnew EventHandler<ThresholdReachedEventArgs^>(SampleHandler::c_ThresholdReached);

    Console::WriteLine("press 'a' key to increase total");
    while (Console::ReadKey(true).KeyChar == 'a') 
        Console::WriteLine("adding one");
        c->Add(1);
    

C#

using System;

namespace ConsoleApplication1

class Program

    static void Main(string[] args)
    
        CppCounter cc = new CppCounter(5);
        //cc.ThresholdReached += cs_ThresholdReached; //<--This is the offending line


        Console.WriteLine("press 'a' key to increase total");
        while (Console.ReadKey(true).KeyChar == 'a')
        
            Console.WriteLine("adding one");
            cc.Add(1);
        
    

    static void cs_ThresholdReached(object sender, ThresholdReachedEventArgs e)
    
        Console.WriteLine("The threshold of 0 was reached at 1.", e.Threshold, e.TimeReached);
        Environment.Exit(0);
    


class Counter

    private int threshold;
    private int total;

    public Counter(int passedThreshold)
    
        threshold = passedThreshold;
    

    public void Add(int x)
    
        total += x;
        if (total >= threshold)
        
            ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
            args.Threshold = threshold;
            args.TimeReached = DateTime.Now;
            OnThresholdReached(args);
        
    

    protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
    
        EventHandler<ThresholdReachedEventArgs> handler = ThresholdReached;
        if (handler != null)
        
            handler(this, e);
        
    

    public event EventHandler<ThresholdReachedEventArgs> ThresholdReached;


  public class ThresholdReachedEventArgs : EventArgs
    
        public int Threshold  get; set; 
        public DateTime TimeReached  get; set; 
    

我做错了什么?是我缺少的东西吗?

【问题讨论】:

我会提出一个非常重要的问题:你真的需要 C++/CLI 吗?你不能用 C# 做吗?根据经验,除非您确切知道自己在做什么,否则 C++/CLI 会很痛苦。并且没有足够的用途来建立知识体系。所以你经常在试探。 乍一看,您的代码看起来是正确的。如果启用This is the offending line,会出现什么错误? 我已经运行了你的代码并且它可以工作。我已经取消了//&lt;--This is the offending line @lgb 库是 dll 还是 lib?如果它们是 dll,并且具有 C 接口,那么您可以尝试直接从 C# 使用它们。很少有 dll 具有 C++ 接口,因为这样做存在兼容性问题。如果您有要链接的 .lib(也很少)并且没有 dll,那么 C++/CLI 是唯一的解决方案。唯一的问题是您必须将 .h 文件转换为 C#...但取决于有多少方法以及您实际使用多少方法,这可能是可行的。 @xanatos 感谢您的帮助,最后问题是在 c# 上重新声明了一个具有相同名称的类,以及一些关于为 AnyCPU 构建而不是显式修复目标架构的问题。 【参考方案1】:
  public class ThresholdReachedEventArgs : EventArgs

代码是正确的,除了这个小故障。您不小心在 C# 代码中重新声明了此类。现在有两个,一个来自您的 C++/CLI 项目,另一个来自您的 C# 项目。这是一个问题,.NET 中的类型标识不仅由命名空间名称和类名称决定,还包括它来自的程序集。

所以这是两种不同的类型,编译器试图告诉你它的 C# 版本不是正确的类型。它们具有相同的名称并不能完全帮助您解码错误消息:)

很容易修复,只需从 C# 代码中删除类声明即可。现在编译器将使用它的 C++/CLI 版本。

【讨论】:

以上是关于在 C++ 中触发事件并在 C# 中处理它们的主要内容,如果未能解决你的问题,请参考以下文章

如何从视图中触发事件(自定义事件)并在 Ext JS 的控制器中处理它们?

从 C# 到 C++ 触发 COM 事件的正确方法是啥

从 C++ DLL 在 C# 中触发事件

C#按钮click事件是如何触发的

在C#中Elapsed是什麽意思?

在 C++ 中创建/打开事件并检查它们是不是被触发