我正在为一些自定义对象添加LINQ接口,但C# compiler fails on type inference。但是,我可以使用原始扩展方法编写等效查询,并且类型推断成功,所以我不确定编译器如何将查询表达式转换为扩展方法调用。
是否有工具或编译器标志,以便我可以查看编译器从我的查询表达式生成的内容,所以我想出来了?
此代码位于开源项目中,因此如果有帮助,我可以提供源代码链接。扩展方法的类型签名的轻微变化避免了这种类型的推理错误,但这些变体没有我所追求的语义。
答案 0 :(得分:4)
您的查询理解代码是:
from f1 in e1
from f2 in e2
from f3 in e3
select f3
您的方法调用代码是:
e1
.SelectMany(f1 => e2)
.SelectMany(f2 => e3), (f2, f3) => f3))
查询转换如下进行。首先,我们处理前两个条款:
from f1 in e1
from f2 in e2
from f3 in e3
select f3;
这被翻译成
from x in ( e1 ) . SelectMany( f1 => e2 , ( f1 , f2 ) => new { f1 , f2 } )
from f3 in e3
select f3;
其中“x”是透明标识符。由于e1,e2或e3都不消耗任何范围变量,因此这是一个透明标识符的事实是无关紧要的;不需要进一步重写来处理透明标识符语义。
然后将该结果转换为
( ( e1 ) . SelectMany( f1 => e2 , ( f1 , f2 ) => new { f1 , f2 } ) )
.SelectMany( x => e3 , ( x , f3 ) => f3 )
我们可以删除其中一些括号:
e1
.SelectMany( f1 => e2 , ( f1 , f2 ) => new { f1 , f2 } ) )
.SelectMany( x => e3 , ( x , f3 ) => f3 )
显然,这与您手动完成的语法转换有很大不同,回想一下,
e1
.SelectMany(f1 => e2)
.SelectMany(f2 => e3), (f2, f3) => f3))
如果将e1,e2,e3替换为上面的实际语法转换,结果表达式是否会传递类型推断?
如果没有,那么问题是“为什么不呢?”您的代码有问题,或类型推导者有问题。如果类型推断器有问题,请告诉我。
如果确实如此,那么问题是“句法转换过程有什么问题”?如果句法转换过程出现问题,请再次告诉我。
谢谢!
答案 1 :(得分:1)
您可以使用Reflector并在关闭优化的情况下查看代码。
答案 2 :(得分:0)
Eric的概述让我了解了如何处理这些查询。问题是我试图以查询翻译不喜欢的方式约束正在操作的类型。
from x in Foo.Bar()
...
Foo.Bar()应该返回Future而x也应该是Future类型,但这不适用于查询转换。我通过添加另一层间接来解决这个问题,基本上包括期货,例如Async< T>类型,只能用期货来实例化,即
public sealed class Async<T> { internal T value; }
public static class Async
{
public static Async<Future<T>> Begin<T>(Future<T> future) { ... }
}
然后我可以在Async值上编写查询计算,因此表达式就像:
from x in Async.Begin(Foo.Bar())
...
其中x现在属于未来类型,我可以强制推迟或推迟期货和承诺。
感谢大家的建议。 Visual Studio中内置的查询表达式转换器会很好,以防MS中的任何人正在阅读此内容。 ; - )