如何在函数中返回一次性对象以确保它在using
块内正常工作?在我的函数中,我想对一次性对象采取行动,并且还要考虑到错误,这会使这一点变得复杂。
到目前为止,我有类似于以下代码:
DBHandle GetDB()
{
/* // I can't do this, because the using block would dispose of my object within this function
using( var db = DatabaseObj.GetHandle() )
{
db.Open();
return db;
}
*/
var db = DatabaseObj.GetHandle();
try
{
db.Open();
return db;
}
catch (Exception ex)
{
db.Dispose();
throw ex;
}
}
// In other code:
using( var obj = GetDB() ){ /* ... */ }
编辑:Posted a more general question与此类似,以免混淆答案和讨论。
答案 0 :(得分:4)
提示:从使用区块返回一次性物体时,请记住 在执行return语句时完成对Dispose()的调用!!!
因此,当它从函数中出来时,从使用块中返回的对象已经被处理掉了。
请参阅以下代码以获取示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class MyDisposable : IDisposable
{
public void DoSomething()
{
Console.WriteLine(" In DoSomething");
}
#region IDisposable Members
public void Dispose()
{
Console.WriteLine(" In Dispose");
}
#endregion
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting Main\n");
Console.WriteLine("Before NormalMethod");
NormalMethod();
Console.WriteLine("After NormalMethod\n");
Console.WriteLine("Before ReturningMethod");
MyDisposable m = ReturningMethod();
m.DoSomething(); // Here the object already has been disposed!
Console.WriteLine("After ReturningMethod\n");
}
private static void NormalMethod()
{
using (MyDisposable myDisposable = new MyDisposable())
{
Console.WriteLine(" In NormalMethod");
}
return;
}
private static MyDisposable ReturningMethod()
{
using (MyDisposable myDisposable = new MyDisposable())
{
Console.WriteLine(" In ReturningMethod");
return myDisposable;
}
}
}
}
这将产生以下输出:
答案 1 :(得分:3)
'使用'正在为你做try / catch工作,只需要db.Open;使用将保证无论它是否抛出,它都将处置你的连接。
答案 2 :(得分:2)
如果DBHandle实现了IDisposable,那么你应该有什么用。
没有'特殊'方式返回IDisposable。
答案 3 :(得分:2)
你有正确的方法,但似乎有点迷失它是怎么回事。
考虑一下你(正确地)说不起作用的代码:
DBHandle GetDB()
{
using( var db = DatabaseObj.GetHandle() )
{
db.Open();
return db;
}
}
此代码几乎相当于:
DBHandle GetDB()
{
var db = DatabaseObj.GetHandle();
try
{
db.Open();
return db;
}
finally
{
if(db != null)//not included if db is a value-type
((IDisposable)db).Dispose();
}
}
这里需要注意的一些事项包括尝试在分配之后才会发生(using
也是如此 - 它不会在{{1并且using
被强制转换为db
,这意味着如果该赋值无效则无法编译,并且IDisposable
可以隐式或显式实现,这将以任何方式工作。
当然,无论是否发生异常,Dispose()
块都会执行。您无法使用finally
,因为它等同于using
,如果发生异常,您希望方法中的finally
。因此,你拿最后一个把它变成一个捕获:
Dispose()
除了添加空检查(也许你可以排除对它的需要)以及我使用裸DBHandle GetDB()
{
var db = DatabaseObj.GetHandle();
try
{
db.Open();
return db;
}
catch
{
if(db != null)
((IDisposable)db).Dispose();
throw;
}
}
(这通常是一个好的)之外,这几乎和你一样想要在不改变或检查异常的情况下重新抛出异常。在某些情况下,抛出新异常会更好,在这种情况下,您应该将原始异常包含在该新异常的throw
属性中,以便向调试的人提供进一步的信息。
总而言之,你走在了正确的轨道上。希望我帮助解释原因。
答案 4 :(得分:1)
返回值只需实现IDisposable
。
实际上,这句话必须是真的:
IDisposable db = GetDB();
如果编译,您可以将GetDB()
放在using
声明中。