3

我有以下代码

    [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;

    }

我的 Maybe 类型接受所有 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 类型结合起来,还是我在这里不走运?完整的 Maybe.cs 实现位于

https://gist.github.com/4016243

4

4 回答 4

6

这个的翻译:

// 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是 a List<Maybe<int>>,因此您需要尝试找到一个SelectMany在此处有效的适当方法。除非您再添加,否则它将查找 in Enumerable.SelectMany,并且那里的每个重载都需要第一个委托返回一个IEnumerable<T>for some T

所以这就是它不起作用的原因。您可以通过制作Maybe<T>实现来使其工作IEnumerable<T>(可能产生单个结果或没有结果)。很难确定这是否是你的目标,但你基本上必须让扩展工作。

或者,您可以为 target 编写一个新的重载SelectManyIEnumerable<T>用于结果是 aMaybe<T>而不是 a 的情况IEnumerable<T>。不过,这将是非常不直观的,IMO。

于 2012-11-05T09:27:36.813 回答
1

您的SelectMany方法将 aMaybe<TSource>作为参数,但您在 a 上使用它List<Maybe<TSource>>,因此它实际上使用了SelectManyfrom 的方法Enumerable。从您的示例中不清楚您期望的类型是什么y,但因为它是代码并没有真正意义。

于 2012-11-05T09:29:19.470 回答
0

正如 Jon 所说,from, fromto的 LINQ 翻译SelectMany是:

var query = l.SelectMany(x => x, (x, y) => y);

首先要注意的是 yourSelectMany是针对一个 individual 定义的Maybe<T>,所以为了有意义,l必须是一个Maybe<T>(对于 some 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;
于 2012-11-05T09:59:51.513 回答
0

对于我的具体问题,事实证明,让 Maybe 实现 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 签名会排列。我还没有被说服。

于 2012-11-05T12:21:51.583 回答