我记得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>
,需要做什么?
答案 0 :(得分:1)
此处的问题是您在T
的实施中重载Where
。
您将T
定义为类型本身的泛型参数,并且还将T
定义为Where
方法的泛型参数。由于该方法的论证是&#34;更接近&#34;它优先。这意味着T
中的Func<T, bool>
是方法论证T
,*而不是类T
。 类 T
为string
,但方法的T
无法推断为任何内容,这就是为什么你&#39 ;没有看到参数的string
成员。
在这种情况下,似乎您根本不需要该方法是通用的,因为类型本身已经为您提供了泛型参数。如果它不是类型本身的扩展方法,那么您只需要该方法是通用的。只是让方法不通用,你的代码就可以了。