monad参与LINQ提供的构图的最低要求是什么?

时间:2016-06-12 19:01:58

标签: c# .net linq

我记得C#编译器在从查询表达式语法转换为调用monad上的相关运算符方法时,并不真正关心并且不需要monad实现某些接口

它甚至不关心运算符方法是扩展还是实例方法。

但我根本无法回想起细节。似乎序列本身只有一个最低要求,在我的查询中,它将是new Foo<string>()表达式。

我记得它并不一定要遵守一个接口,但它要么必须有一个名为GetEnumerator的方法,要么必须实现IEnumerator<T>方法。但我可能错了,因为我的示例查询在GetEnumerator类中存在或不存在Foo<T>方法的情况下工作。

但是,当我引入where查询表达式时,这并不能解析接收者的类型。

Select表达式运行正常。

我曾经知道这一点,直到18个月前,这是我实施一个简单的LINQ提供商的时候。我已经忘记了很多。

请列出所有这些的最低要求吗?

using System;

namespace CompilerDoesNotCareAboutTypeLINQQuerySyntax
{
    class Program
    {
        static void Main(string[] args)
        {

            // What are the minimum requirements on Foo<T>()?
            // How does it resolve this expression new Foo<string>
            // such that it knows that Foo<string> has many Bar<string>
            // or whatever foo in the query below might resolve to?
            var query = from foo in new Foo<string>()
                        /* where foo. // when I do foo., only the system.object inherited properties of Foo show up */
                        select foo;
        }
    }

    public class Foo<T>
    {
        public string Name { get; set; }

        public Foo<T> Where<T>(Func<T, bool> predicate)
        {
            return new Foo<T>();
        }

        /*IEnumerator<Foo<T>> GetEnumerator()
        {
            return new List<Foo<T>>().GetEnumerator();
        }*/
    }

    public static class Extensions
    {
        public static Foo<R> Select<T, R>(this Foo<T> foo, Func<T, R> transformer)
        {
            return new Foo<R>();
        }
    }
}

更新

这是在实施Servy指出的修复后的Where方法声明的更新。

class Foo<T>
{
  public Foo<T> Where(Func<T, bool> predicate)
  {
    return new Foo<T>();
  }
}

修复了由于上述查询表达式查询中的foo已解析为system.object而导致的错误。但是,它现在解析为string,通过推断,它是Where方法的泛型类型参数类型。

它之前解析为object,因为我已经像Servy指出的那样重载了泛型类型参数T,现在它解析为T,这是声明的泛型类型参数输入Foo<T>

问题仍然存在: 序列表达式new Foo<string>()的最低要求是什么?看起来没有?那么位于序列位置的表达式的值与范围变量foo的类型之间的相关性是什么?如果我必须使new Foo<T>返回许多foos ,那么查询foo中的from foo in new Foo<T>()...会解析为单个Foo<T>,需要做什么?

1 个答案:

答案 0 :(得分:1)

此处的问题是您在T的实施中重载Where

您将T定义为类型本身的泛型参数,并且T定义为Where方法的泛型参数。由于该方法的论证是&#34;更接近&#34;它优先。这意味着T中的Func<T, bool>是方法论证T,*而不是类T Tstring,但方法的T无法推断为任何内容,这就是为什么你&#39 ;没有看到参数的string成员。

在这种情况下,似乎您根本不​​需要该方法是通用的,因为类型本身已经为您提供了泛型参数。如果它不是类型本身的扩展方法,那么您只需要该方法是通用的。只是让方法不通用,你的代码就可以了。