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
没有评论:
发表评论