简体   繁体   中英

Best practices with events in C#

In C#, you can have a return value in your event function. However, you only receive the return value of the last event. Also, there doesn't appear to be a way to get the return value of the previous event.

What are some good practices? Should I always use void ? From my limited experience if I want to chain values must I use ref ?

How might I write an event? I wanted to use Func<ref t, returnT>, but ref is illegal there, and I imagine action is the same way. (I ended up with the below). Is there a way to make the event one line instead of two when using a ref ?

    delegate int FuncType(ref int a);
    static event FuncType evt;
    static void Main(string[] args)
    {
        evt += foo;
        var aa = 1;
        var a = evt(ref aa);
        evt += bar;
        var bb = 1;
        var b = evt(ref bb);
    }

    static int foo(ref int a)
    {
        a = a*3;
        return a;
    }

    static int bar(ref int a)
    {
        a=a +1;
        return a;
    }

As said you can use GetInvocationList which will allow you to call each method individually and process returned data.

But before that please consider using EventHandler<T> with EventArgs .

You can have " everything " you need to be returned in EventArgs . Check this sample code :

public class BalanceChangedEventArgs : EventArgs
{
    public readonly double OldBalance;
    public readonly double NewBalance;

    public BalanceChangedEventArgs(double oldB, double newB)
    {
        OldBalance = oldB;
        NewBalance = newB;
    }
}

public class Account
{
    private double balance;

    public EventHandler<BalanceChangedEventArgs> balanceChanged;

    protected void OnBalanceChanged(BalanceChangedEventArgs eArgs)
    {
        if (balanceChanged != null)
            balanceChanged(this, eArgs);
    }

    public double Balance
    {
        get { return balance; }
        set
        {
            if (balance == value)
                return;

            OnBalanceChanged(new BalanceChangedEventArgs(balance, value));

            balance = value;
        }
    }
} 

Don't confuse "event" with "callback". If you're wanting to provide a "hook" for customization, then consider one of the following:

  • A base class with virtual methods for hooks.
  • An interface for a callback object passed in to your constructor or accessed via a property.
  • A delegate passed in to your constructor or accessed via a property.

If you've considered the above, and still want to use an event, then you could include the "result" as part of your event argument type, eg, e.Result or e.Handled . You still have the issue of multiple event handlers possibly overwriting each other's values, so you should combine that approach with iterating the invocation list as suggested by other answers. Either collate all the results or have an "early exit" strategy like what is used for e.Handled .

您可能需要查看Microsoft的Event Design文档。

If you want to get the return values when an event has multiple subscribers, use Delegate.GetInvocationList . Then you can say

foreach(FuncType d in evt.GetInvocationList()) {
    int value = d(parameter);
    // do something with value
}

However, in general, it's best to avoid return values in event handlers.

The 'best practice' is to only use void eventhandlers. Precisely because of the last-value-only problem.

If you want combined results, define an EventArgs descendant with appropriate properties. Use a list or sum values or something.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM