>我有以下代码
[Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod]
public void TestEnumOfMaybe()
{
List<Maybe<int>> l = new List<Maybe<int>>();
l.Add(1.ToMaybe());
l.Add(Maybe.None<int>());
l.Add(3.ToMaybe());
var y = from x in l
from y in x
select y;
}
我的 May 类型接受所有 Select 和 SelectMany 方法,以使其与 Linq 兼容,并且我有测试来证明这一点。但是,我似乎无法像上面的测试用例那样找到一种进行跨类型 LINQ 组合的方法。我得到的错误是
expression of type 'FunctionalExtensions.Maybe<int>' is not allowed in
a subsequent from clause in a query expression with source type
'System.Collections.Generic.List<FunctionalExtensions.Maybe<int>>'.
Type inference failed in the call to 'SelectMany'.
FunctionalExtensions*
有没有办法将这两种 LINQ 类型结合起来,还是我在这里不走运?完整的也许.cs实现在
https://gist.github.com/4016243
这个的翻译:
// Changed variable from y to query for clarity
var query = from x in l
from y in x
select y;
很简单:
var query = l.SelectMany(x => x, (x, y) => y);
请注意,此处没有调用任何y
。
现在l
是一个List<Maybe<int>>
,所以你需要尝试找到一个合适的SelectMany
方法,这种方法在这里是有效的。除非您添加了更多内容,否则它将以Enumerable.SelectMany
查找,并且那里的每个重载都需要第一个委托返回某些T
的IEnumerable<T>
。
所以这就是它不起作用的原因。您可以通过使Maybe<T>
实现IEnumerable<T>
(大概产生单个结果或没有结果)来使其工作。很难确定这是否是你的目标,但你基本上必须让这种扩展发挥作用。
或者,您可以为SelectMany
目标IEnumerable<T>
编写新的重载,用于结果是Maybe<T>
而不是IEnumerable<T>
的情况。不过,这将是非常不直观的,IMO。
您的SelectMany
方法将Maybe<TSource>
作为参数,但您是在List<Maybe<TSource>>
上使用它,因此它实际上使用了Enumerable
中的SelectMany
方法。从您的示例中不清楚您期望的y
类型是什么,但是由于它是代码,
正如 Jon 所指出的,from
的 LINQ 翻译from
SelectMany
是:
var query = l.SelectMany(x => x, (x, y) => y);
首先要注意的是,您的SelectMany
是针对单个Maybe<T>
定义的,因此要使其有意义,l
必须是Maybe<T>
(对于某些T
),而不是列表。接下来要注意的是签名必须匹配。例如:
public static Maybe<TResult> SelectMany<TSource, TMaybe, TResult>(
this Maybe<TSource> m, Func<Maybe<TSource>, Maybe<TMaybe>> f,
Func<Maybe<TSource>, Maybe<TMaybe>, TResult> g)
{
throw new NotImplementedException();
// return m.Bind(x => f(x).Bind(y => g(x, y).ToMaybe()));
}
和:
var obj = l[0];
现在这有效(显式泛型):
var q = obj.SelectMany<int, int, Maybe<int>>((x => x), (x, y) => y);
这与:
var r = obj.SelectMany((x => x), (x, y) => y);
这与:
var query = from x in obj
from y in x
select y;
对于我的特定问题,事实证明,也许实现IEnumerable是要走的路,它也使支持IOBservable变得微不足道。我的两个测试用例现在通过了。
[Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod]
public void TestEnumOfMaybe()
{
List<Maybe<int>> l = new List<Maybe<int>>();
l.Add(1.ToMaybe());
l.Add(Maybe.None<int>());
l.Add(3.ToMaybe());
var k = from q in l
from y in q
select y;
k.Should().BeEquivalentTo(new[] { 1, 3 });
}
[Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod]
public void TestObservableOfMaybe()
{
List<Maybe<int>> l = new List<Maybe<int>>();
l.Add(1.ToMaybe());
l.Add(Maybe.None<int>());
l.Add(3.ToMaybe());
var o = l.ToObservable();
var k = from q in o
from y in q
select y;
var m = k.ToEnumerable();
m.Should().BeEquivalentTo(new[] { 1, 3 });
}
总的来说,我认为 LINQ 系统禁止将不同类型的签名链接在一起,即使 SelectMany 签名会对齐。否则我还没有被说服。