【发布时间】:2021-01-16 02:02:30
【问题描述】:
Nullable<T> 有如下扩展方法。
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);
}
}
}
这允许在查询语法中使用Nullable<T>。
以下测试将通过。
[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);
}
但是,如果您尝试链接 3 个或更多,它将被视为匿名类型并且不会编译。
[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);
}
您可以通过手动指定使用ValueTuple 来解决此问题,如下所示,但这很难看。
[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);
}
这些简化的例子可以简单地使用+操作符来解决:var q = nv1 + nv2 + nv3;
但是,如果您可以流利地编写用户定义的结构,您会发现使用它会更方便。有什么好办法吗?
【问题讨论】: