有两种方法,其中一种方法在using
语句中使用LINQ返回数据。我想知道查询是否有可能抛出某种异常,因为查询执行是延迟的,而它正在使用的变量已经被处理掉了?
class Foo
{
void Bar()
{
var bazResult = Baz();
//... use bazResult here...
}
IEnumerable<int> Baz()
{
using (var d = new SomeDisposableSource())
{
return d.Select(e => e.Id);
}
}
}
顺便说一句,它必须已经以某种形式提出,但我找不到明显的候选人。所以不要太费力地踢我:)答案 0 :(得分:4)
我认为如果对象被处理,你会有例外。 This thread非常相似,并提供了几种处理问题的方法。简单的一个是强制执行return d.Select(e => e.Id).ToList()
,但可能不适合你
答案 1 :(得分:2)
是的,它可以抛出异常,但这取决于“SomeDisposableSource”的实现。在调用Dispose()之前,您要求源获取IEnumerable或Array,但实际上您在Dispose之后枚举每个元素,因此如果它抛出并且异常与否取决于该“yeld-return”的实际代码码。 (它是否使用任何处置过的物体?)
你可以通过以下方式解决它(具有更高的内存使用率):
return d.Select(e => e.Id).ToArray();
这样,在执行Dispose()之前,所有枚举都已完成。
编辑:使用:
return d.Select(e => e.Id).ToList();
......可能会更好。
答案 2 :(得分:0)
whether it's possible
是一个奇怪的问题。对的,这是可能的。您的SomeDisposableSource
可能会在GetEnumerator
方法中检查是否已将其处理掉。
答案 3 :(得分:0)
我认为Gerardo走在正确的轨道上,但我会对它进行不同的编码,这可能会导致更小的内存占用:
return d.Select(e => e.Id).ToList();
编辑:哎呀! IndigoDelta远远领先于我
答案 4 :(得分:0)
您将(更多)确定性using
语句与(不太确定的)LINQ语句混合在一起。通过将资源d
包装在using
语句中,您明确声明在方法结束时您希望将其处理掉。
因此,如果您希望确保在退出方法之前处置d
,则必须立即使用ToArray
,ToList
或某些方式执行LINQ执行其他方法。
更难稍微多一些(每个评论者)路径将创建一个允许资源(IEnumerable<T>
)的自定义d
使用LINQ语句返回并在以后执行,即调用者现在负责处置IEnumerable<T>
(通常只是通过使用foreach
块)。
答案 5 :(得分:0)
事实上,您的代码中的执行不会延迟,因为您使用的是常规return
。
所以Baz
方法执行,返回和处理。稍后,当您枚举结果时,如果此枚举机制依赖于已处置的非托管资源(在您的示例中很可能就是这种情况),则会失败。
解决方法很简单:不要使用return
阻止延迟执行,而是使用yield return
。这是推迟执行的准确关键字。
你的方法就变成了这个
IEnumerable<int> Baz()
{
using (var d = new SomeDisposableSource())
{
//return d.Select(e => e.Id); //Baaaad ! No proper deferred execution
foreach (var i in d.Select(e => e.Id)) yield return i; //Proper deferred execution
}
}
然后一切都好。在枚举完成之前,using
不会调用Dispose
方法。