[英]iterating through disposable objects
以下是遍历一次性对象的安全方法吗? 还是会导致物体残废? 等等? 如果我使用dispose语句而不是使用嵌套怎么办?
public static void Main()
{
foreach (ChildObject oChild in webApp)
{
//On Noes! Unexpected Error!
}
}
public static IEnumerable<ChildObject> SafelyGetNextObjInWebApp(WebApplication webApp)
{
foreach (ParentObject oParent in webApp.Parents)
{
using (parent)
{
foreach (ChildObject oChild in oParent.Children)
{
using (oChild)
{
yield return oChild;
}
}
}
}
}
除非调用者枚举SafelyGetNextObjInWebApp()
返回的所有对象,否则您的方法并不安全。 请考虑以下语句中发生的情况:
ChildObject o = SafelyGetNextObjInWebApp(arg).First();
在这种情况下, SafelyGetNextObjInWebApp()
将在yield
语句处停止,并且永远不会继续。 因此,该调用将不会处理该对象。
如果要使用迭代器一次返回一个由Web服务创建的对象,则应确保该调用是异常安全的,并强加处理该迭代器调用的调用者。 为了显示:
public IEnumerable<ParentObject> GetParents(WebApplication webApp)
{
// assumes webApp.Parents uses deferred execution.
return webApp.Parents;
}
public void ProcessParent(WebApplication webApp)
{
foreach (ParentObject p in GetParents())
{
// Assumes p.Dipsose() calls ChildObject.Dispose() for all p.ChildObjects.
using(p)
{
foreach (ChildObject o in p.ChildObjects)
{
// do something with o
}
}
}
}
}
毕竟,“安全”方法可能不太安全。 如果迭代在所有父对象和子对象都被迭代之前中断(或失败)怎么办? 剩余的对象将不会被处置(至少不会以该特定方法处置)。
似乎应该将迭代和处置分开保存。 您将拥有更简洁的代码,并且可以更好地控制程序的工作。
还有更多...
C#迭代器模式将使“安全”方法以微妙的方式失败。 yield
子对象之后,程序将有效地“退出”正在using {...}
块,从而处理该子对象,从而使通过迭代SafelyGetNextObjInWebApp()
得到它的任何人都无法使用它。
可以做什么
从SafelyGetNextObjInWebApp()
中SafelyGetNextObjInWebApp()
using
语句。 将产生的子对象封装在“知道”何时处置子项的“工作单元”类中。
在使用您的代码块的末尾执行一个dispose,因此在函数的末尾使用或使用dispose的结果相同
您的代码可能没问题,但可能会在正常使用中引起问题:您将返回将在下一次迭代中处理的对象。 因此,如果您的呼叫者的代码看起来像
foreach(var i in SafelyGetNextObjInWebApp())
{
if (IsInteresting(i))
{
interestingItems.Add(i);
}
}
// here interestingItems contains disposed items you can't use.
通过提供迭代所有项目并以Action<T>
作为参数的方法来反转代码可能会突出表明必须在动作内部完成每个项目的处理这一事实。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.