我试图理解为什么这个linq不编译(fundInvoices不可见):
Dictionary<Fund, IEnumerable<Invoice>> paidfundInvoices;
...
from fundInvoices in paidfundInvoices
from p in fundInvoices.Value
group p by p.VendorId into ps
select new Payment
{
FundId = fundInvoices.Key.FundId, // ERROR here
Value = ps.Sum(p => p.Amount)
}
Run Code Online (Sandbox Code Playgroud)
所以我继续将其更改为匿名类型用法,并且基金发票在这里神奇可见:
from fundInvoices in paidfundInvoices
select new
{
Fund = fundInvoices.Key,
Payments = from p in fundInvoices.Value
group p by p.VendorId into ps
select new Payment
{
FundId = fundInvoices.Key.FundId, // NO ERROR
Value = ps.Sum(p => p.Amount)
}
};
Run Code Online (Sandbox Code Playgroud)
但是这种匿名类型似乎是多余的,我没有使用它.我只需要一个支付对象的平面列表.但是我的代码只编译那种方式......
Eri*_*ert 14
我试图理解为什么这个linq不编译
理解的关键是阅读关于如何将查询降低到普通代码的规范部分.
让我们从您的查询开始:
from fundInvoices in paidfundInvoices
from p in fundInvoices.Value
group p by p.VendorId into ps
select new Payment {
FundId = fundInvoices.Key.FundId, // ERROR here
Value = ps.Sum(p => p.Amount)
}
Run Code Online (Sandbox Code Playgroud)
好的,第一步.规范中的规则是:
带有continuation的查询表达式
from … into x …被翻译成from x in ( from … ) …
您的查询现在
from ps in (
from fundInvoices in paidfundInvoices
from p in fundInvoices.Value
group p by p.VendorId)
select new Payment {
FundId = fundInvoices.Key.FundId, // ERROR here
Value = ps.Sum(p => p.Amount)
}
Run Code Online (Sandbox Code Playgroud)
现在应该清楚为什么fundInvoices不在select子句的范围内.fundInvoices是一个完全不同的查询的范围变量.
但是,如果不清楚,让我们继续前进.下一条规则是:
表单的查询表达式
from x in e select v被翻译成( e ) . Select ( x => v )
您的查询现在
((from fundInvoices in paidfundInvoices
from p in fundInvoices.Value
group p by p.VendorId))
.Select(ps =>
new Payment {
FundId = fundInvoices.Key.FundId,
Value = ps.Sum(p => p.Amount)
})
Run Code Online (Sandbox Code Playgroud)
现在我们可以翻译内部查询:
将带有第二个from子句的后跟不是select子句的查询表达式
from x1 in e1 from x2 in e2 …转换为from * in ( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => new { x1 , x2 } ) …
这*是一个"透明的标识符",我们将在一分钟内看到它的含义.
您的查询现在
((from * in (paidfundInvoices).SelectMany(
fundInvoices => fundInvoices.Value,
(fundInvoices, p) => new {fundInvoices, p})
group p by p.VendorId))
.Select(ps =>
new Payment {
FundId = fundInvoices.Key.FundId,
Value = ps.Sum(p => p.Amount)
})
Run Code Online (Sandbox Code Playgroud)
最终规则:
表单的查询表达式
from x in e group v by k被翻译成( e ) . GroupBy ( x => k , x => v )
所以那是
((((paidfundInvoices).SelectMany(
fundInvoices => fundInvoices.Value,
(fundInvoices, p) => new {fundInvoices, p}))
.GroupBy(* => p.VendorId, * => p)))
.Select(ps =>
new Payment {
FundId = fundInvoices.Key.FundId,
Value = ps.Sum(p => p.Amount)
})
Run Code Online (Sandbox Code Playgroud)
的*意思是"使一对在select-许多选入范围的匿名类型的成员的该Desugar和删除不必要的括号和我们有查询的最终形式:
paidfundInvoices
.SelectMany(
fundInvoices => fundInvoices.Value,
(fundInvoices, p) => new {fundInvoices, p})
.GroupBy(pair => pair.p.VendorId, pair => pair.p)))
.Select(ps =>
new Payment {
FundId = fundInvoices.Key.FundId,
Value = ps.Sum(p => p.Amount)
})
Run Code Online (Sandbox Code Playgroud)
现在应该非常清楚为什么fundInvoices不在延续范围内.这将是在范围GroupBy得益于透明标识符脱糖,但它是不是在所有的范围中Select.
更一般地说:在LINQ范围中,通常从左边的声明流到右边的用法,但是有一些例外:into从范围中移除范围变量,而不是所有范围变量都在范围内的所有位置join,等等.阅读规范了解更多详情.
| 归档时间: |
|
| 查看次数: |
294 次 |
| 最近记录: |