从事件中返回一个值 - 这是一个好的做法吗?

时间:2009-07-30 23:59:00

标签: c# multithreading events delegates

我正在做一个使用异步TCP套接字的小型多线程应用程序,但我会明白:我正在使用自定义事件从表单中读取值,并且事件使用的委托返回字符串完成后。

我的问题是:这是正确的吗?可以从事件中返回值吗?或者有更好的方法吗? (比如使用表单的简单委托来读取值)

9 个答案:

答案 0 :(得分:37)

从事件返回值通常很尴尬。在实践中,我发现在一组传递给事件的自定义EventArgs上包含一个可写属性要容易得多,然后在事件触发后检查 - 类似于WinForms FormClosing事件的Cancel属性。

答案 1 :(得分:28)

我认为这不是一个好主意......事件基本上是多播代理,因此可以有多个处理程序。在这种情况下你会得到哪个回报值?

答案 2 :(得分:16)

我能想到的最接近的例子是WinForms中的FormClosing事件。它允许表单通过将eventArgs.Cancel属性设置为true来取消事件。为了让你做类似的事情,你可以定义你自己的事件args类,返回值作为该类的属性。然后每当你举起事件时传递一个事件args对象。提出事件的人可以检查事件args对象的返回值。接收事件的其他人也可以检查或更改事件args对象。

更新:我刚遇到AppDomain.AssemblyResolve事件,它似乎是一个返回值的事件。您似乎只需要声明一个返回值的委托类型,然后使用该委托类型定义您的事件。不过,我还没有尝试创建自己的事件。在事件参数上使用属性的一个优点是事件的所有订阅者都可以看到之前订阅者返回的内容。

答案 3 :(得分:13)

我知道这是在帖子之后的年龄,但想到添加评论和代码来解释Dustin Campbell的答案,如果其他人遇到这个帖子的话。我在尝试决定什么是最佳实践时遇到了这篇文章,这就是答案的含义。

创建您自己的自定义事件处理程序类

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 ;
    }
}

因此,当您创建事件委托时,您可以使用您创建的事件args。

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
    }
}

答案 4 :(得分:10)

注意:只有最后一个事件才会返回结果。

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;
    }        
}

答案 5 :(得分:8)

我不知道这是不是最佳做法,但我是这样做的。

   Func<DataRow, bool> IsDataValid;

   // some other code ....

   isValid = true;
   if (IsDataValid != null)
   {
      foreach (Func<DataRow, bool> func in IsDataValid.GetInvocationList())
      {
         isValid &= func(Row);
      } 
   }

答案 6 :(得分:1)

如果事件返​​回一个值并且有多个处理程序已注册,则事件将返回上次调用的处理程序的结果值。 在http://blogs.msdn.com/b/deviations/archive/2008/11/27/event-handlers-returning-values.aspx

上查找示例

答案 7 :(得分:0)

我像这样循环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);
            }
        }

答案 8 :(得分:-1)

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)
    }
}