8

I have 2 classes which looks like this:

class Widget
{
    string Selected { get; set; }

    List<Option> Options { get; set; }
}

class Option
{
    string InternalCode { get; set; }

    string ExternalCode { get; set; }
}

Options gets populated dynamically with different data per client for showing ExternalCode as options

Selected gets populated with ExternalCode.

I then need to access the InternalCode which matches.

At present I am doing this:

var option = widget.Options.SingleOrDefault(o => o.ExternalCode == widget.Selected);

var internalCode = option == null ? string.Empty : option.InternalCode;

Is this possible using a single line using Null Coalesce?

Shevek
  • 3,869
  • 5
  • 43
  • 63
  • Why the null check on option? it's never null or a possible NullReferenceException – Sievajet Jan 06 '16 at 10:37
  • @Sievajet It can be null if no matching option is found - SingleOrDefault will return default(T) in that scenario, which will be null for this case. – RB. Jan 06 '16 at 10:38

4 Answers4

18

Yes, you can use the null propagation and null coalescing operator, which suits your needs if you can use C# 6:

var option = widget.Options
             .SingleOrDefault(o => o.ExternalCode == widget.Selected)?.InternalCode
             ?? string.Empty;

The ?. will translate to your use of the option == null ? part.

Brian
  • 25,523
  • 18
  • 82
  • 173
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • Awesome! Thank you. I couldn't figure out where to access the property. The `?.Property` is what I was missing. – Shevek Jan 06 '16 at 10:38
  • The code showed so far does not work in cases where there is a matching instance of `Option` with `InternalCode == null` – Michael Rätzel Jan 06 '16 at 18:13
9

Sure, with a small change:

var option = widget.Options
                   .Where(o => o.ExternalCode == widget.Selected)
                   .Select(o => o.InternalCode)
                   .FirstOrDefault() ?? "";

In other words, project the sequence of matching options to a sequence of internal codes, and then take the first of those, defaulting to null... which allows you to use the null-coalescing operator on the result.

You can use the null-conditional operator as per Patrick's answer instead, but personally I'd prefer the code in this answer - I think it's simpler to understand.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

You can do this if you wrote extension method:

public static class MonadExtensions
{
    public static TResult With<TSource, TResult>(TSource source, Func<TSource, TResult> action) where TSource : class
        {
            if (source != default(TSource))
                return action(source);
            return default(TResult);
        }
}

And use it:

var internalCode  = widget.Options.SingleOrDefault(o => o.ExternalCode == widget.Selected).With(o=>o.InternalCode)??"";
Kirill Bestemyanov
  • 11,946
  • 2
  • 24
  • 38
0

Is this possible using a single line using Null Coalesce?

Yes, here is how:

var option = (widget.Options.SingleOrDefault(o => o.ExternalCode == widget.Selected) ?? new Option() { InternalCode = string.Empty }).InternalCode;

The other answers using a single statement I have seen so far yield wrong results in cases where there is a matching instance of Option with InternalCode == null

Michael Rätzel
  • 401
  • 1
  • 6
  • 17