2009-09-18 137 views
19

我试图写入API,当我从表中获取数据时需要调用事件处理程序。事情是这样的:通过EventHandler返回返回值

public override bool Run(Company.API api) 
    { 
     SomeInfo _someInfo = new SomeInfo(); 

     if (_someInfo.Results == 1) 
      return true; 
     else 
      return false; 

     using (MyTable table = new MyTable(api)) 
     { 
      table.WhenData += new EventHandler<DataEventArgs<Record>>(table_WhenData); 
      table.WhenDead += new EventHandler<EventArgs>(table_WhenDead); 
      table.Start(); 
     } 

    public void table_WhenData(object sender, DataEventArgs<Record> e) 
    { 
     return true; 
    } 

具有即时通讯是我不知道如何传递一个返回值从table_WhenData回到Run方法的问题。

我试过很多方法(如试图将_someInfo传递给方法),但我似乎无法得到正确的语法。

任何建议,非常感谢。

+0

事件处理程序如预期从某处调用。这不是在你的代码中显示?这是唯一可以检查处理程序返回的地方。 – simon 2009-09-18 18:46:17

+0

谢谢大家。因为这是一个API,有很多代码没有访问权限,或者我无法更改。我只是想在将它发回给开发者之前进行验证。谢谢。 – 2009-09-18 19:03:52

+2

用户名加上1 – 2015-12-18 13:19:42

回答

38

这里的常见模式不是从事件处理程序返回任何数据,而是为事件参数对象添加属性,以便事件的使用者可以设置调用者可以访问的属性。这在UI处理代码中非常常见;你会在整个地方看到取消事件的概念。

以下是伪代码,未编译就绪。其目的是展示这种模式。

public MyEventArgs : EventArgs 
{ 
    public bool Cancel{get;set;} 
} 

public bool fireEvent() 
{ 
    MyEventArgs e=new MyEventArgs(); 

    //Don't forget a null check, assume this is an event 
    FireEventHandler(this,e); 

    return e.Cancel; 
} 

public HandleFireEvent(object sender, MyEventArgs e) 
{ 
e.Cancel=true; 
} 

编辑

我喜欢乔恩斯基特如何措辞是:使EventArgs mutuable。也就是说,事件的消费者可以修改对象的状态,从而允许事件的发起者获取该数据。

+1

如果有多个事件处理程序(有些将其设置为true,另一个则将此对象值设置为false,对于上面给出的代码示例),事件订阅者代码如何确定?就像是最后一个订阅者赢得的那样 – bashahul 2016-06-11 07:08:57

+1

好的问题你可能会想要在这种情况下使用不同的数据结构,具体取决于你拥有的业务规则 – JoshBerke 2016-06-13 13:32:32

15

你可以做到这一点的唯一方法是使其中一个参数(最好是“参数”而不是发送者)可变。如果它还不是可变的,那么你基本上就会遇到问题 - 没有办法将信息输出。

(好的,有一种方法 - 你可以保持事件参数本身不变,但让它的一个成员变成一个方法,最终调用代码注册的代码首先提升事件,但这太可怕了。 ..)

+2

我的头痛会试图理解一种方式,请让EventArgs变得可变! – JoshBerke 2009-09-18 18:50:28

+0

如何在我的回复中描述使用闭包? – 2009-09-18 18:51:41

+0

伊戈尔:这将工作,但通常需要结果的代码位不是预订事件的代码位。 – 2009-09-18 18:57:52

1

一个简单的解决方案是使用封闭:

public override bool Run() { 
    SomeInfo someInfo = ... 
    table.WhenData += (obj, args) => { 
     someInfo.Return = something 
    }; 
} 
+0

我对这个解决方案可能有的担心是并发问题。一个线程调用该事件,另一个线程在写入完成之前读取someInfo变量。它需要某种类型的多线程保护。 – simon 2009-09-19 00:51:33

17

我知道这是一个古老的职位,但以防万一有人遇到它,它肯定是有可能做到这一点。你声明你自己的委托,它返回一个值,然后根据这个新委托来关闭事件。下面是一个例子:

在事件庄家/出版者:

// the delegate 
public delegate string ReturnStringEventHandler(object sender, EventArgs args); 
// the event 
public event ReturnStringEventHandler StringReturnEvent; 
// raise the event 
protected void OnStringReturnEvent(EventArgs e) 
    { 
     if (StringReturnEvent != null) // make sure at least one subscriber 
       // note the event is returning a string 
       string myString = StringReturnEvent(this, e); 
    } 

在事件订阅者:

// Subscribe to event, probably in class constructor/initializer method 
StringReturnEvent += HandleStringReturnEvent; 

// Handle event, return data 
private string HandleStringReturnEvent(object sender, EventArgs e) 
{ 
    return "a string to return"; 
} 

.NET提供在AssemblyResolve事件的一个例子,它使用ResolveEventHandler委托返回数据,在这种情况下是对所需Assembly的引用。 MSDN Article on AssemblyResolve event

我曾亲自使用两个AssemblyResolve事件和自定义委托技术,从事件中返回的数据,他们都工作在Visual Studio 2010中

+2

如果使用自定义委托方法,如果有多个处理程序返回不同的值,会发生什么情况?事件提升者收到哪个返回值? – Shavais 2013-12-05 20:27:10

+0

您提到了这种方法的明确缺点。要在事件中注册的最后一个事件处理程序是其值将被返回的那个。 http://msdn.microsoft.com/en-us/library/aa691375%28VS.71%29.aspx在我提到的“AssemblyResolve”事件中,这是可以的,因为它的唯一意图是一次只能使用一个,但你是对的 - 一般来说,如果需要多个返回值,这将是一个糟糕的设计选择。 – AFischbein 2013-12-06 14:48:55

+0

辉煌。谢谢 ! – BillW 2014-03-23 16:26:21