从事件中返回一个值——这有啥好的做法吗?
Posted
技术标签:
【中文标题】从事件中返回一个值——这有啥好的做法吗?【英文标题】:Return a value from an Event -- is there a Good Practice for this?从事件中返回一个值——这有什么好的做法吗? 【发布时间】:2010-11-15 15:39:00 【问题描述】:我正在做一个使用异步 TCP 套接字的小型多线程应用程序,但我要直截了当:我正在使用自定义事件从表单中读取值,并且事件使用的委托返回一个完成后的字符串。
我的问题是:这是正确的吗?从事件中返回值可以吗?还是有更好的方法来做到这一点? (比如使用简单的表单委托来读取值)
【问题讨论】:
【参考方案1】:从事件返回值通常很尴尬。在实践中,我发现在传递给事件的一组自定义 EventArgs 中包含可写属性要容易得多,然后在事件触发后进行检查——类似于 WinForms FormClosing 事件的 Cancel 属性。
【讨论】:
能否详细说明include a writable property on a set of custom EventArgs that is passed to the event
部分?
@Odys 自定义 EventArgument 对象。创建结果所在的属性。【参考方案2】:
我认为这不是一个好主意...事件基本上是多播委托,因此可以有多个处理程序。在这种情况下,您将采用哪个返回值?
【讨论】:
【参考方案3】:我知道这是帖子发布后的年龄,但我想用代码添加评论来解释达斯汀坎贝尔的答案,如果其他人遇到这个帖子。我在尝试确定最佳实践时遇到了这篇文章,这就是答案的含义。
创建您自己的自定义事件处理程序类
public class myCustomeEventArgs:EventArgs
public bool DoOverride get; set;
public string Variable1 get; private set;
public string Variable2 get; private set;
public myCustomeEventArgs(string variable1 , string variable2 )
DoOverride = false;
Variable1 = variable1 ;
Variables = variable2 ;
因此,当您创建事件委托时,您可以像这样使用您创建的事件参数。
public delegate void myCustomeEventHandler(object sender, myCustomeEventArgs e);
并在引发事件的类中声明该事件。
public event myCustomeEventHandler myCustomeEvent;
因此,当您在类中触发事件时,侦听事件的类可以在事件主体中设置 e.DoOverride = true;因为它将在触发事件的类中声明。
例如火灾事件:
if(myCustomeEvent != null)
var eventArgs = new myCustomeEventArgs("Some Variable", "Another Varaible");
myCustomeEvent(this, eventArgs);
//Here you can now with the return of the event work with the event args
if(eventArgs.DoOverride)
//Do Something
【讨论】:
你怎么知道活动什么时候“回归”? 事件在引发它们的同一线程上运行。运行myCustomeEvent(...)
的代码会将控制权(在同一线程上运行)传递给所有订阅的事件处理程序。一旦他们的所有代码都运行完毕,控制权将在调用myCusomeEvent(...)
后立即返回到指令。如果没有订阅者,或者有订阅者将事件重新广播到另一个线程,则eventArgs
上的所有属性都将具有其默认值(bool
为 false,字符串为 null
)。 【参考方案4】:
我能想到的最接近的例子是 WinForms 中的 FormClosing 事件。它允许表单通过将 eventArgs.Cancel 属性设置为 true 来取消事件。为了让您做类似的事情,您可以定义自己的事件 args 类,并将返回值作为该类的属性。然后在引发事件时传递一个事件 args 对象。引发事件的人可以检查事件 args 对象的返回值。接收事件的其他人也可以检查或更改事件 args 对象。
更新:我刚刚遇到了AppDomain.AssemblyResolve 事件,它似乎是一个返回值的事件。似乎您只需要声明一个返回值的委托类型,然后使用该委托类型定义您的事件。不过,我还没有尝试过创建自己的活动。在 event 参数上使用属性的一个好处是,该事件的所有订阅者都可以看到以前的订阅者返回了什么。
【讨论】:
注意:您可以使用任何委托来定义事件,因此也可以定义像public event Func<string, string, bool> SomeEvent;
这样可以调用为bool r = SomeEvent("foo", "bar");
的事件【参考方案5】:
注意:只有最后一个事件返回结果。
class Program
static event Func<string, bool> TheEvent;
static void Main(string[] args)
TheEvent += new Func<string, bool>(Program_TheEvent);
TheEvent +=new Func<string,bool>(Program_TheEvent2);
TheEvent += new Func<string, bool>(Program_TheEvent3);
var r = TheEvent("s"); //r == flase (Program_TheEvent3)
static bool Program_TheEvent(string arg)
return true;
static bool Program_TheEvent2(string arg)
return true;
static bool Program_TheEvent3(string arg)
return false;
【讨论】:
谢谢。跨 WCF 服务为我工作【参考方案6】:我不知道这是否是最佳做法,但我是这样做的。
Func<DataRow, bool> IsDataValid;
// some other code ....
isValid = true;
if (IsDataValid != null)
foreach (Func<DataRow, bool> func in IsDataValid.GetInvocationList())
isValid &= func(Row);
【讨论】:
【参考方案7】:如果事件返回一个值并且注册了多个处理程序,则事件返回最后调用的处理程序的结果值。 在http://blogs.msdn.com/b/deviations/archive/2008/11/27/event-handlers-returning-values.aspx 中查找示例
【讨论】:
答案中的链接已失效 - “找不到页面”。【参考方案8】:我像这样循环了 EventArgs 的属性并提取了它的 X 和 Y 值。
private void navBarControl1_Click(object sender, EventArgs e)
int _x = 0;
int _y = 0;
Type t = e.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(t.GetProperties());
foreach (PropertyInfo prop in props)
if (prop.Name == "X")
object propValue = prop.GetValue(e, null);
_x = Convert.ToInt32(propValue);
if (prop.Name == "Y")
object propValue = prop.GetValue(e, null);
_y = Convert.ToInt32(propValue);
【讨论】:
【参考方案9】:void method()
list<string> strings = new list<string>();
dostuff += stuff;
dostuff += stuff;
dostuff(this, new EventHandlerArgs() Parameter = strings )
foreach(string currString in strings)
//....
void stuff(object sender, EventHandlerArgs e)
list<string> strings = e.Parameter as list<string>;
if (strings != null)
strings.Add(MyString)
【讨论】:
欢迎来到***!最好为示例代码提供简短描述以提高发布准确性:)以上是关于从事件中返回一个值——这有啥好的做法吗?的主要内容,如果未能解决你的问题,请参考以下文章