C# 从事件返回一个值——有没有好的做法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1210026/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 10:59:53  来源:igfitidea点击:

Return a value from an Event -- is there a Good Practice for this?

c#multithreadingeventsdelegates

提问by Hugo

I'm doing a small multi-threaded app that uses asynchronous TCP sockets, but I will get to the point: I'm using a custom event to read a value from a form and the delegate used by the event returns a string when finished.

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

My question here is: is that correct? is it OK to return values from the events? or is there a better way to do this? (like using a simple delegate to the form to read the values)

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

采纳答案by Dustin Campbell

It's often awkward to return values from events. In practice, I've found it much easier to include a writable property on a set of custom EventArgs that is passed to the event, and then checked after the event fires -- similar to Cancel property of the WinForms FormClosing event.

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

回答by Don Kirkby

The closest example I can think of is the FormClosing event in WinForms. It lets the form cancel the event by setting the eventArgs.Cancel property to true. For you to do something similar, you would define your own event args class with the return value as a property on that class. Then pass an event args object whenever you raise the event. Whoever raised the event can inspect the event args object for the return value. Others who are receiving the event can also inspect or change the event args object.

我能想到的最接近的例子是 WinForms 中的 FormClosing 事件。它通过将 eventArgs.Cancel 属性设置为 true 来让表单取消事件。为了做类似的事情,您可以定义自己的事件 args 类,并将返回值作为该类的属性。然后在引发事件时传递事件 args 对象。引发事件的任何人都可以检查事件 args 对象的返回值。其他接收事件的人也可以检查或更改事件 args 对象。

Update:I just ran across the AppDomain.AssemblyResolveevent, and it appears to be an event that returns a value. It seems you just need to declare a delegate type that returns a value, and then define your event with that delegate type. I haven't tried creating my own event like this, though. One advantage to using a property on the event argument is that all subscribers to the event can see what previous subscribers have returned.

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

回答by Thomas Levesque

I don't think it's a good idea... events are basically multicast delegates, so there can be multiple handlers. Which return value will you take in that case ?

我认为这不是一个好主意……事件基本上是多播委托,因此可以有多个处理程序。在这种情况下,您将采用哪个返回值?

回答by Henk

I don't know if this is best practice but i did it this way.

我不知道这是否是最佳实践,但我是这样做的。

   Func<DataRow, bool> IsDataValid;

   // some other code ....

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

回答by dude

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

回答by Riaan Swart

I know this is ages after the post but thought of adding comment with code to explain Dustin Campbell answer for if someone else comes across this thread. I came across this post while trying to decide what would be best practice and this is what is meant by the answer.

我知道这是帖子发布后的很长时间了,但我想添加带有代码的评论来解释达斯汀坎贝尔的答案,如果其他人遇到这个线程。我在尝试确定最佳实践时遇到了这篇文章,这就是答案的含义。

Create your own custom event handler class

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

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

So when you create your event delegate you use your created event args like this.

因此,当您创建事件委托时,您可以像这样使用创建的事件参数。

public delegate void myCustomeEventHandler(object sender, myCustomeEventArgs e);

And in the class raising the event you declare the event.

在引发事件的课程中,您声明了该事件。

public event myCustomeEventHandler myCustomeEvent;

So when you trigger the event in your class the class that listens for the event you can just in the body of the event set e.DoOverride = true; as it will be declared in the class firing the event.

因此,当您在类中触发事件时,侦听事件的类就可以在事件主体中设置 e.DoOverride = true; 因为它将在触发事件的类中声明。

Fire event for example:

火灾事件例如:

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

回答by sammybar

If event returns a value and there are multiple handlers registered the event returns the result value of the last called handler. Look for an example at http://blogs.msdn.com/b/deviations/archive/2008/11/27/event-handlers-returning-values.aspx

如果事件返​​回一个值并且注册了多个处理程序,则该事件返回最后调用的处理程序的结果值。在http://blogs.msdn.com/b/deviations/archive/2008/11/27/event-handlers-returning-values.aspx寻找一个例子

回答by Alatey

Note: only the last event returns the result.

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

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

回答by user1218233

I looped the properties of the EventArgs like this and pulled out its X and Y values.

我像这样循环了 EventArgs 的属性并提取了它的 X 和 Y 值。

private void navBarControl1_Click(object sender, EventArgs e) { int _x = 0; int _y = 0;

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