【问题标题】:Modifying a struct passed to an event handler?修改传递给事件处理程序的结构?
【发布时间】:2012-03-28 12:50:32
【问题描述】:

这似乎是一个我不明白的非常基本的概念。

在为键盘驱动程序编写 .NET 包装器时,我会为按下的每个键广播一个事件,如下所示(下面的简化代码):

// The event handler applications can subscribe to on each key press
public event EventHandler<KeyPressedEventArgs> OnKeyPressed;
// I believe this is the only instance that exists, and we just keep passing this around
Stroke stroke = new Stroke();

private void DriverCallback(ref Stroke stroke...)
{
    if (OnKeyPressed != null)
    {
        // Give the subscriber a chance to process/modify the keystroke
        OnKeyPressed(this, new KeyPressedEventArgs(ref stroke) );
    }

    // Forward the keystroke to the OS
    InterceptionDriver.Send(context, device, ref stroke, 1);
}

Stroke 是一个struct,其中包含按键的扫描码和一个状态。

在上面的代码中,由于我通过引用传递值类型结构,因此对结构所做的任何更改在传递给操作系统时都将被“记住”(以便可以拦截和修改按下的键)。所以没关系。

但是如何让我的OnKeyPressed 事件的订阅者修改struct Stroke

以下不起作用:

public class KeyPressedEventArgs : EventArgs
{
    // I thought making it a nullable type might also make it a reference type..?
    public Stroke? stroke;

    public KeyPressedEventArgs(ref Stroke stroke)
    {
        this.stroke = stroke;
    }
}

// Other application modifying the keystroke

void interceptor_OnKeyPressed(object sender, KeyPressedEventArgs e)
{
    if (e.stroke.Value.Key.Code == 0x3f) // if pressed key is F5
    {
        // Doesn't really modify the struct I want because it's a value-type copy?
        e.stroke.Value.Key.Code = 0x3c; // change the key to F2
    }
}

提前致谢。

【问题讨论】:

  • 使stroke 可以为空只是将您的实际值放入一个包装器中,该包装器包含一个指示值是否存在的布尔值。包装的值从一开始就一直是值类型。
  • 对于@EricJ. 的评论,可空类型本身也是值类型,尽管值类型从编译器中得到了很多特殊处理。

标签: c# c#-4.0 event-handling struct pass-by-reference


【解决方案1】:

在 KeyPressedEventArg 的构造函数中传递结构是通过引用传递的,但就是这样,只要修改了 stroke 变量,它就会通过值传递。如果你一直通过ref 传递这个结构,你可能需要考虑为它创建一个包装类。从长远来看,更好的设计决策。

【讨论】:

    【解决方案2】:

    这样的事情可能会奏效:

    if (OnKeyPressed != null)     
    {         
      // Give the subscriber a chance to process/modify the keystroke         
      var args = new KeyPressedEventArgs(stroke);
      OnKeyPressed(this, args);     
      stroke = args.Stroke;
    } 
    

    给您的订阅者一份副本,然后在他们完成后将其复制回您的本地值。

    或者,您可以创建自己的代表击键的类并将其传递给订阅者吗?

    【讨论】:

    • 完美运行,抱歉这个简单的问题。
    猜你喜欢
    • 1970-01-01
    • 2012-08-30
    • 1970-01-01
    • 2018-08-03
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    相关资源
    最近更新 更多