以下是一种迭代一次性物体的安全方法吗?或者这会导致不适的物体?等等?如果我使用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;
}
}
}
}
}
答案 0 :(得分:4)
除非您的来电者通过SafelyGetNextObjInWebApp()
返回的所有对象进行枚举,否则您的方法不安全。考虑以下陈述中发生的事情:
ChildObject o = SafelyGetNextObjInWebApp(arg).First();
在这种情况下,SafelyGetNextObjInWebApp()
的执行将在yield
语句处停止,并且永远不会继续。因此,该调用不会处理该对象。
如果要使用迭代器一次一个地返回Web服务创建的对象,则应确保调用是异常安全的,并强制迭代器调用者调用dispose。举例说明:
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
}
}
}
}
}
答案 1 :(得分:3)
毕竟,“安全”方法可能不会更安全。如果在迭代所有父对象和子对象之前迭代中断(或失败)会怎么样?其余的物品不会被处理掉(至少不是那种特定的方法)。
似乎应该将迭代和处理分开。您将拥有更清晰的代码,并可以更好地控制程序正在执行的操作。
还有更多......
C#迭代器模式将使“安全”方法以微妙的方式失败。在yield
子对象之后,程序将有效地“退出”using {...}
块,从而处理子进程,使其无法通过迭代SafelyGetNextObjInWebApp()
获得它。
可以做什么
从using
中取出SafelyGetNextObjInWebApp()
语句。将生成的子对象封装在“知道”何时处置子女的“工作单元”类中。
答案 2 :(得分:1)
在块的最后使用你执行一个dispose,所以在你的函数结束时使用或使用dispose之间的结果相同
答案 3 :(得分:1)
您的代码可能没问题,但可能会导致正常使用中出现问题:您将返回将在下次迭代时处理的对象。因此,如果您的来电者的代码看起来像
foreach(var i in SafelyGetNextObjInWebApp())
{
if (IsInteresting(i))
{
interestingItems.Add(i);
}
}
// here interestingItems contains disposed items you can't use.
通过提供迭代所有项目并将Action<T>
作为参数的方法来反转代码可以突出显示每个项目的处理必须在操作内完成的事实。