Skip to content

ActionFuncConversions

David Arno edited this page Jun 27, 2016 · 1 revision

Action/Func conversions


Introduction to Succinc<T>'s Action/Func conversion methods

void is a strange beast in C#. The consequence of a method or lambda being void, means nothing is returned. If one if writing imperative-style code, this generally doesn't matter. But step into the functional world, and this can become a problem. A void method cannot be assigned to a Func delegate; nor can it be used in ternary expressions. Succinc<T> provides a means of working around these limitations, as discussed here.

ToUnitFunc methods

The ToUnitFunc methods can be used to cast an Action lambdas/method groups (from 0 to 4 parameters) to a Func delegate that returns unit.

These methods can be used in any situation where some piece of code requires a Func and you want to use an Action. For example, Succinc<T> uses these methods to halve the number of classes needed to handle pattern matching. Rather than have classes that handle Exec matches and Result matches respectively, in the former case, all the Action methods involved are cast to Func<...,Unit> lambdas and used with the same classes as the Result matchers.

These methods are implemented as extension methods to the Action types. A contrived example of their use is:

var func = Action(int x => Console.WriteLine(x)).ToUnitFunc();
// func has the type Func<int,Unit>

These methods can also be used in conjunction with Ignore() (described next) to allow the use of actions/void methods in ternary expressions.

Unit.Ignore() method

Ignore is one of those "use with caution" features. It allows you to specify any expression and ignore the result if there is one. Most of the time, you shouldn't be ignoring return values from functions and the like. There are edge cases though where it is useful. By way of example, consider the following method:

void IOptionActionMatcher<T>.Exec()
{
    if (_union.Case == Variant.Case1)
    {
        _case1FunctionSelector.DetermineResultUsingDefaultIfRequired(_union.Case1);
    }
    else
    {
        _case2FunctionSelector.DetermineResultUsingDefaultIfRequired(_union.Case2);
    }
}

Using Ignore, this can be rewritten to use the ternary operator:

void IOptionActionMatcher<T>.Exec()
{
    Ignore(_union.Case == Variant.Case1
        ? _case1FunctionSelector.DetermineResultUsingDefaultIfRequired(_union.Case1)
        : _case2FunctionSelector.DetermineResultUsingDefaultIfRequired(_union.Case2));
}

(which is how the method is really written in the OptionMatcher<T, TResult> class.

You can’t perform that action at this time.