Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to null check c# 7 tuple in LINQ query?

Tags:

c#

linq

c#-7.0

Given:

class Program {     private static readonly List<(int a, int b, int c)> Map = new List<(int a, int b, int c)>()     {         (1, 1, 2),         (1, 2, 3),         (2, 2, 4)     };      static void Main(string[] args)     {         var result = Map.FirstOrDefault(w => w.a == 4 && w.b == 4);          if (result == null)             Console.WriteLine("Not found");         else             Console.WriteLine("Found");     } } 

In the above example, a compiler error is encountered at line if (result == null).

CS0019 Operator '==' cannot be applied to operands of type '(int a, int b, int c)' and '<null>'

How would I go about checking that the tuple is found prior to proceeding in my "found" logic?

Prior to using the new c# 7 tuples, I would have this:

class Program {     private static readonly List<Tuple<int, int, int>> Map = new List<Tuple<int, int, int>>()     {         new Tuple<int, int, int> (1, 1, 2),         new Tuple<int, int, int> (1, 2, 3),         new Tuple<int, int, int> (2, 2, 4)     };      static void Main(string[] args)     {         var result = Map.FirstOrDefault(w => w.Item1 == 4 && w.Item2 == 4);          if (result == null)             Console.WriteLine("Not found");         else             Console.WriteLine("Found");     } } 

Which worked fine. I like the more easily interpreted intention of the new syntax, but am unsure on how to null check it prior to acting on what was found (or not).

like image 468
Kritner Avatar asked Jun 01 '17 12:06

Kritner


People also ask

How can I use null in C?

In practice, NULL is a constant equivalent to 0 , or "\0" . This is why you can set a string to NULL using: char *a_string = '\0'; Download my free C Handbook!

What does == null mean in C?

In computer programming, null is both a value and a pointer. Null is a built-in constant that has a value of zero. It is the same as the character 0 used to terminate strings in C.

Does C have null pointer?

A null pointer is a pointer which points nothing. Some uses of the null pointer are: a) To initialize a pointer variable when that pointer variable isn't assigned any valid memory address yet.

Is null false C?

Yes. NULL evaluates to false, since C considers any non-zero value true and any zero value false.


1 Answers

Value tuples are value types. They can't be null, which is why the compiler complains. The old Tuple type was a reference type

The result of FirstOrDefault() in this case will be a default instance of an ValueTuple<int,int,int> - all fields will be set to their default value, 0.

If you want to check for a default, you can compare the result with the default value of ValueTuple<int,int,int>, eg:

var result=(new List<(int a, int b, int c)>()             {                 (1, 1, 2),                 (1, 2, 3),                 (2, 2, 4)             }         ).FirstOrDefault(w => w.a == 4 && w.b == 4);  if (result.Equals(default(ValueTuple<int,int,int>))) {     Console.WriteLine("Missing!");  } 

WORD OF WARNING

The method is called FirstOrDefault, not TryFirst. It's not meant to check whether a value exists or not, although we all (ab)use it this way.

Creating such an extension method in C# isn't that difficult. The classic option is to use an out parameter:

public static bool TryFirst<T>(this IEnumerable<T> seq,Func<T,bool> filter, out T result)  {     result=default(T);     foreach(var item in seq)     {         if (filter(item)) {             result=item;             return true;          }     }     return false; } 

Calling this can be simplified in C# 7 as :

if (myList.TryFirst(w => w.a == 4 && w.b == 1,out var result)) {     Console.WriteLine(result); } 

F# developers can brag that they have a Seq.tryPick that will return None if no match is found.

C# doesn't have Option types or the Maybe type (yet), but maybe (pun intended) we can build our own:

class Option<T>  {     public T Value {get;private set;}      public bool HasValue {get;private set;}      public Option(T value) { Value=value; HasValue=true;}          public static readonly Option<T> Empty=new Option<T>();      private Option(){}      public void Deconstruct(out bool hasValue,out T value)     {         hasValue=HasValue;         value=Value;     } }  public static Option<T> TryPick<T>(this IEnumerable<T> seq,Func<T,bool> filter)  {     foreach(var item in seq)     {         if (filter(item)) {             return new Option<T>(item);          }     }     return Option<T>.Empty; } 

Which allows writing the following Go-style call:

var (found,value) =myList.TryPick(w => w.a == 4 && w.b == 1); 

In addition to the more traditional :

var result=myList.TryPick(w => w.a == 4 && w.b == 1); if (result.HasValue) {...} 
like image 97
Panagiotis Kanavos Avatar answered Sep 24 '22 23:09

Panagiotis Kanavos