2021年1月15日星期五

Custom Nullable

There are extension methods for Nullable<T> like below.

using System;  using System.Runtime.CompilerServices;    namespace DoNotationish  {      public static class NullableExtensions      {          public static U? Select<T, U>(this T? nullableValue, Func<T, U> f)              where T : struct              where U : struct          {              if (!nullableValue.HasValue) return null;              return f(nullableValue.Value);          }            public static V? SelectMany<T, U, V>(this T? nullableValue, Func<T, U?> bind, Func<T, U, V> f)              where T : struct              where U : struct              where V : struct          {              if (!nullableValue.HasValue) return null;              T value = nullableValue.Value;              U? bindValue = bind(value);              if (!bindValue.HasValue) return null;              return f(value, bindValue.Value);          }      }  }  

This allows Nullable<T> to be used in query syntax. The following tests will pass.

        [Test]          public void Test1()          {              int? nv1 = 5;              int? nv2 = 3;              var q = from v1 in nv1                      from v2 in nv2                      select v1 + v2;              Assert.AreEqual(8, q);          }            [Test]          public void Test2()          {              int? nv1 = null;              int? nv2 = 3;              var q = from v1 in nv1                      from v2 in nv2                      select v1 + v2;              Assert.IsNull(q);          }  

However, if you try to chain 3 or more, it will be treated as an anonymous type and will not compile.

        [Test]          public void Test3()          {              int? nv1 = 5;              int? nv2 = 3;              int? nv3 = 8;              var q = from v1 in nv1                      from v2 in nv2  // Error CS0453: anonymous type is not struct                      from v3 in nv3                      select v1 + v2 + v3;              Assert.AreEqual(16, q);          }  

You can work around this issue by manually specifying to use ValueTuple as below, but this is ugly.

        [Test]          public void Test3_()          {              int? nv1 = 5;              int? nv2 = 3;              int? nv3 = 8;              var q = from v1 in nv1                      from v2 in nv2                      select (v1, v2) into temp      // ugly                      from v3 in nv3                      select temp.v1 + temp.v2 + v3; // ugly              Assert.AreEqual(16, q);          }  

These simplified examples can be solved simply by using the + operator: var q = nv1 + nv2 + nv3;

However, you would find it more convenient to work with user-defined structs if you could write it fluently. Is there any good way?

https://stackoverflow.com/questions/65745802/custom-nullablet-extension-methods-and-selectmany January 16, 2021 at 10:02AM

没有评论:

发表评论