交叉类型 LINQ

  • 本文关键字:LINQ 类型 .net linq
  • 更新时间 :
  • 英文 :


>我有以下代码

[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查找,并且那里的每个重载都需要第一个委托返回某些TIEnumerable<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 翻译fromSelectMany是:

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 签名会对齐。否则我还没有被说服。

最新更新