Getting all results from Func call

2020-04-28 08:19发布

The concept of delegates aren't too new to me but I cannot seem to find out how to get all results from a Func delegates. More specifically, I have a class that has a Func delegate that returns a type bool. Something like this...

private Func<Employee, Shift, bool> qualificationCheckCallback;

There are both 'register' and 'unregister' methods for the callback as well. My goal is to see if any of the methods stored in the delegate return false when invoked later in code. Any insight you may have on this issue is much appreciated! Thanks.

标签: c# delegates
3条回答
戒情不戒烟
2楼-- · 2020-04-28 08:38

As mentioned in Andrew's answer, if you simply invoke qualificationCheckCallback like a normal method, you'll only get back the return value from one of the methods. For this reason, it's pretty unusual to have multicast delegates that have a return value.

If your goal is to see if at least one of the methods stored in your delegate returns false, you'll need to invoke the methods individually. Here is one way to do that using the Delegate.GetInvocationList() method:

bool hasAtLeastOneFalse = false;
if (qualificationCheckCallback != null)
{
    foreach(var f in qualificationCheckCallback.GetInvocationList()
                                               .Cast<Func<Employee, Shift, bool>>())
    {
        if (!f(employee, shift))
        {
            hasAtLeastOneFalse = true;
            // break; // If you don't care about invoking all delegates, you can choose to break here.
        }
    }
}

Console.WriteLine(hasAtLeastOneFalse);

I'm not suggesting this is a good practice, but it can be done.

查看更多
Bombasti
3楼-- · 2020-04-28 08:51

A quick search on MSDN found this thread:

https://social.msdn.microsoft.com/Forums/en-US/38a638fe-4a7d-44d6-876c-729d90c20737/how-to-get-return-value-from-delegate?forum=csharplanguage

The problem with events is that the return values cannot be fully trusted. You will get only one return value no matter how many subscribers that you have for the event. The central issue is that you cannot reliably determine which subscriber produced the return value. The beauty of the .NET Event Model is the anonymity that it uses. That means event subscribers are completely abstracted from the event publishers.

查看更多
虎瘦雄心在
4楼-- · 2020-04-28 08:52

You are using the wrong pattern. I'd recommend storing a list of these delegates and iterating over the list, rather than using multidelegates to call multiple targets.

You can make this work (if you need to) by changing the signature to include a "state" variable that is passed by reference to each caller:

private Action<Employee, Shift, QualCheckState> qualificationCheckCallback;

public class QualCheckState { public bool Passed { get; set; } }

// Call it thus:
var state = new QualCheckState { Passed = true }; // Hope for the best
qualificationCheckCallback(someEmployee, someShift, state);
if (state.Passed) {
    // Assume everyone passed
}

Keep in mind, this requires the callees to honor the signature, and not overwrite anyone else's failed state:

public void SomeCallee(Employee e, Shift s, State state) {
   // If some other check failed, don't bother doing our check.
   if (!state.Passed) return;
   // Do some check here
   if (checkFailed) state.Passed = false;
}

Of course, you can also extend this pattern to make it safer:

public class QualCheckState {
    private List<bool> _results = new List<bool>();
    public bool Passed { get { return _results.All(s => s); }
    public void RecordResult(bool result) {
        _results.Add(result);
    }
}
查看更多
登录 后发表回答