【问题标题】:Pass extra parameters to an event handler?将额外参数传递给事件处理程序?
【发布时间】:2021-05-30 05:39:54
【问题描述】:

假设我想在分配事件处理程序时传递一些额外的数据。考虑以下代码:

private void setup(string someData)
{
     Object.assignHandler(evHandler);
}

public void evHandler(Object sender)
{
    // need someData here!!!
}

如何将someData 加入我的evHandler 方法?

【问题讨论】:

标签: c# events callback


【解决方案1】:
private void setup(string someData)
{
     Object.assignHandler((sender) => evHandler(sender,someData));
}
public void evHandler(Object sender, string someData)
{
    // need someData here!!!
}

【讨论】:

  • 这是一个很好的解决方案,但是如果 EventHandler 已经有 TArgs 怎么办。如 += new EventHandler(evHandler)?
  • 嗨@Lily,您的要求并不完全清楚。最好发布一个更详细的问题(而不是评论)和一些代码来演示您正在尝试做什么。
  • 谢谢,这解决了我遇到的一个问题,但我是 C# 新手,所以您介意解释一下这种语言结构是什么,或者给我一个关键字让谷歌解释一下吗?
  • @TomSmilack,看看 lambda 表达式和使用闭包捕获变量。基本上,lambda 表达式是声明方法的一种简写方式(……还有更多,但这是另一回事)
  • 这个问题我有一个比较标准的解决方案,第一个答案:stackoverflow.com/questions/14058412/…
【解决方案2】:

我很难弄清楚上面@spender 的例子,尤其是:Object.assignHandler((sender) => evHandler(sender,someData));,因为从字面上看,没有Object.assignHandler 这样的东西。所以我做了更多的谷歌搜索,找到了this example。 Peter Duniho 的回答让我印象深刻(这不是我的工作):

剪辑

通常的方法是使用带有事件处理程序的匿名方法 有你修改过的签名。例如:

void Onbutton_click(object sender, EventArgs e, int i) { ... }

button.Click += delegate(object sender, EventArgs e) 
{ Onbutton_click(sender, e, 172); };

当然不用传入172,甚至不做第三个参数 一个整数。 :)

/snip

使用该示例,我能够使用 lambda 表示法将两个自定义 ComboBoxItem 对象传递给 Timer.Elapsed 事件:

simulatorTimer.Elapsed +=
(sender, e) => onTimedEvent(sender, e,
(ComboBoxItem) cbPressureSetting.SelectedItem,
(ComboBoxItem) cbTemperatureSetting.SelectedItem);

然后进入它的处理程序:

static void onTimedEvent(object sender, EventArgs e, ComboBoxItem pressure, ComboBoxItem temperature)
    {
        Console.WriteLine("Requested pressure: {0} PSIA\nRequested temperature: {1}° C", pressure, temperature);
    }

这不是上面示例中的任何新代码,但它确实演示了如何解释它们。希望像我这样的人会发现它有启发性和有用性,这样他们就不会像我一样花费数小时试图理解这个概念。

此代码在我的项目中有效(除了 ComboBoxItem 对象的非线程安全异常,我不相信它会改变示例的工作方式)。我现在想通了。

【讨论】:

  • 唯一的问题是,如果您想取消订阅该事件(并且很可能应该),您将通过匿名代表取消订阅,您不应该这样做 - 请参阅 @987654322 @.
【解决方案3】:

捕获的变量:

private void setup(string someData)
{
    Object.assignHandler((sender,args) => {
        evHandler(sender, someData);
    });
}

public void evHandler(Object sender, string someData)
{
    // use someData here
}

或(C# 2.0 替代方案):

    Object.assignHandler((EventHandler)delegate(object sender,EventArgs args) {
        evHandler(sender, someData);
    });

【讨论】:

  • 被捕获变量===闭包?
  • @Matt - 是的,捕获的变量是词法闭包。
  • 澄清一下,第一个解决方案对 C# .NET 2.0 无效吗?
  • @whydna 第一个解决方案需要 C# 3.0 或更高版本;有一个微妙的语法添加
【解决方案4】:

您可以尝试这样做:

string yourObject;

theClassWithTheEvent.myEvent += (sender, model) =>
{
 yourObject = "somthing";
}

【讨论】:

    【解决方案5】:

    我的类似问题被标记为重复,所以我想在这里添加一个答案,因为它不会让我回答我的问题。

    class Program
        {
            delegate void ComponentEventHandler(params dynamic[] args);
    
            event ComponentEventHandler onTest;
    
            static void Main(string[] args)
            {  
                Program prg = new Program();
    
                // can be bound to event and called that way
                prg.onTest += prg.Test;
                prg.onTest.Invoke("What", 5, 12.0);
    
                Console.ReadKey();
            }
    
            public void Test(params dynamic[] values)
            {
                // assign our params to variables
                string name = values[0];
                int age = values[1];
                double value = values[2];
    
                Console.WriteLine(name);
                Console.WriteLine(age);
                Console.WriteLine(value);
            }
        }
    

    【讨论】:

      【解决方案6】:

      好吧,让someData成为成员变量的最简单方法id如下:

      public class MyClass
      {
          private string _eventData;
      
          private void setup(string someData) 
          {
             _eventData = someData;
             Object.assignHandler(evHandler);
          }
      
          public void evHandler()
          {
              // do something with _eventData here
          }
      }
      

      我不确定这是不是最好的方法,但这确实取决于事件类型、对象等。

      【讨论】:

      • 正在考虑这个方法,但是 setup 可能会使用不同的 someData 调用多次。每个处理程序的数据应该是唯一的。
      • 在那种情况下,spender 或 Marc 的解决方案要好得多
      【解决方案7】:

      您可以创建一个具有基于 Object 的附加属性的自定义对象:

      class CustomObject : Object
      {
          public string SomeData;
      }
      
      private void setup(string someData)
      {
          CustomObject customObject = new CustomObject { SomeData = someData };
          CustomObject.assignHandler(evHandler);
      }
      
      public void evHandler(Object sender)
      {
          string someData = ((CustomObject)sender).SomeData;
      }
      

      如果初始化后数据不应该再改变,你也可以添加一个自定义的构造函数,例如。

      【讨论】:

        【解决方案8】:

        这是我将额外参数传递给计时器处理程序的单行解决方案。

        private void OnFailed(uint errorCode, string message)
        {
            ThreadPoolTimer.CreateTimer((timer) => {
            UI.ErrorMessage = string.Format("Error: 0x{0:X} {1}", errorCode, message);
            }, System.TimeSpan.FromMilliseconds(100));
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-08-30
          • 1970-01-01
          • 2012-09-01
          相关资源
          最近更新 更多