我收到一个用户的错误日志,其中包含一个我不完全理解的堆栈跟踪。以下是的外观
Stack Trace:
at ...Presenters.Forms.PresenterHome.<GetCounts>b__f(IActivityItem activityItem)
at System.Linq.Enumerable.Count[TSource](IEnumerable`1 source, Func`2 predicate)
at ...Presenters.Forms.PresenterHome.GetCounts(Int32& completeCount, Int32& incompleteCount)
at ...Presenters.Forms.PresenterHome.UpdateSummaryPanel()
.....
(为了保护客户端的身份,我删除了一些名称空间的开头)
我不明白的部分是<GetCounts>b__f(...)
,以及为什么它在Enumerable.Count[...](...)
之后被调用。我认为这与Count
谓词有关,但我无法完全解读。
如果有帮助,则异常为InvalidCastException
。以下是所涉及的一些代码(为了保护身份,稍作修改)。
void UpdateSummaryPanel()
{
int completeCount;
int incompleteCount;
GetCounts(out completeCount, out incompleteCount);
...
}
private void GetCounts(
out int completeCount,
out int incompleteCount)
{
incompleteCount = _applicationContext.ActivityItems.Count(
activityItem => activityItem.ActivityType == ActivityTypes.Foo
&& ((FooActivity) activityItem).Status != CaptureStatus.Bar);
// similar code for other count
}
值得一提的是,我很确定我知道是什么导致了错误(即坏的强制转换在哪里),但我真正好奇的是堆栈跟踪中的<GetCounts>b__f(...)
成员。
如果您使用Reflector、dotPeek等打开程序集,您会看到编译器已将GetCounts
中lambda表达式的逻辑放入另一个方法中,在本例中为<GetCounts>b__f
。这对于lambda表达式和匿名方法来说是完全正常的,其他一些C#特性(迭代器块、匿名类型、自动实现的方法等)也会自动为您创建成员。
名称中的尖括号很好地表明它是编译器生成的:编译器使用一个无法形容的名称-一个不是有效标识符的名称-以确保不仅不会与其他成员发生任何冲突,而且您永远无法在代码中引用这些"隐藏"成员。
这意味着它在编译器生成的东西中,在本例中是一个匿名委托。更具体地说,编译器正在您的类型上生成一个名为<GetCounts>b__f
的方法。