Alex Gordon
Alex Gordon

Reputation: 60841

how to return a typed tuple depending on which variable is not null?

How can we implement pattern matching in order to return a tuple?

Currently method signature

public static string Match(string nodeName, string nodeValue, string sourceParty, 
    string destinationParty, List<Translation> translations)

Desired Method Signature

public static (string, TypeOfMatch) Match(string nodeName, string nodeValue, 
    string sourceParty, string destinationParty, List<Translation> translations)

I have the following static method:

public static class Matcher
{
    public static string Match(string nodeName, string nodeValue, string sourceParty, 
        string destinationParty, List<Translation> translations)
    {
        //please excuse the pseudo code in these 3 lines
        var exactMatch = from.translations(where xyz).select.Take(1)
        var defaultMatch = from.translations.select(where abc).Take(1)
        var anySourceMatch = from.translations.select(where sss).Take(1)

        return exactMatch.FirstOrDefault() ??
            defaultMatch.FirstOrDefault() ??
            anySourceMatch.FirstOrDefault() ??
            nodeValue;
    }
}

I would like to know the type of match that was returned (whether it was exact/default/anySource).

Right now we are returning string, but perhaps the return should be a tuple such as (TypeOfMatch, string) where TypeOfMatch would be an enum such as:

public enum TypeOfMatch
{
    Exact, Default, AnySource
}

but then our return statement would be something like:

if (exactMatch.FirstOrDefault() != null)
    return (TypeOfMatch.Exact, exactMatch.First());

if (defaultMatch.FirstOrDefault() != null)
    return (TypeOfMatch.Default, defaultMatch.First());

// etc.

Is there a more robust way of doing a switch on which of the variables were not null and then returning the pair (TypeOfMatch, string)?

Upvotes: 1

Views: 140

Answers (1)

Douglas
Douglas

Reputation: 54897

The challenge with your scenario is that value tuples are value types, and therefore cannot be combined using the null-coalescing operator, ??, which only works on nullable types. However, you could define an extension method to convert your value tuple into a nullable value type, which could then be subjected to ??.

I am assuming that your Translation class has an implicit type conversion to string; otherwise, you need to call ToString() or read a string property when constructing your value tuples.

public static class Matcher
{
    public static (TypeOfMatch, string) Match(
        string nodeName, string nodeValue, string sourceParty,
        string destinationParty, List<Translation> translations)
    {
        return
            translations.Where(xyz).Select(t => (TypeOfMatch.Exact, t)).FirstOrNull() ??
            translations.Where(abc).Select(t => (TypeOfMatch.Default, t)).FirstOrNull() ??
            translations.Where(sss).Select(t => (TypeOfMatch.AnySource, t)).FirstOrNull() ??
            (TypeOfMatch.NodeValue, nodeValue);
    }
}

public static class EnumerableExtensions
{
    public static T? FirstOrNull<T>(this IEnumerable<T> source)
        where T : struct
    {
        return source.Cast<T?>().FirstOrDefault();
    }
}

Upvotes: 2

Related Questions