我使用常规的Sql*
对象来查询数据库:
// conn is a SqlConnection
// transaction is a SqlTransaction
using(var cmd = new SqlCommand(someSelectQuery, conn, transaction))
using(var reader = cmd.ExecuteReader())
{
...
}
我要写一个包装器,将new SqlCommand()
和cmd.ExecuteReader()
包装在一起:
using(var someNewReader = GetSelectReader(someSelectQuery, conn, transaction))
{
...
}
问题是:这个“ someNewReader”对象(或struct?)应该:
SqlDataReader
相同的方法.Dispose()
方法,该方法同时处理了基础SqlCommand
和SqlDataReader
我尝试过的事情
我尝试创建一个包装类,其中包含两个字段,一个SqlCommand
和一个SqlDataReader
,以及:
SqlDataReader
.Dispose()
方法,该方法以正确的顺序处理两个对象以正确的方式重新实现.Dispose()
(尤其是:以正确的方式处理异常,并且仍然尝试.Dispose()
每个人)会增加编码开销,该开销容易出错,但是会遵循每个.Dispose()
链的精确smae结构。
问题
我想知道是否有一种机制可以将多个IDisposable
对象“链接在一起”,这种东西可以让我描述一下:
obj
是Disposable
parent
是Disposable
obj
(至少具有相同的公共接口),但可以正确调用obj.Dispose()
,然后调用parent.Dispose()
答案 0 :(得分:-1)
我认为没有一种简单的方法可以使包装纸满足您的第一个条件: 1.以某种方式发布与SqlDataReader相同的方法
但是,您可以返回一个一次性容器并访问其项目,这样就无需实现包装程序:
class DisposableTupleContainer<D1, D2>: IDisposable
where D1 : IDisposable
where D2 : IDisposable
{
private bool _disposed = false;
private (D1, D2) _items;
public D1 Item1 => _disposed ? throw new ObjectDisposedException("d1") : _items.Item1;
public D2 Item2 => _disposed ? throw new ObjectDisposedException("d2") : _items.Item2;
public DisposableTupleContainer(D1 d1, Func<D1,D2> d2)
// add try catch to destroy d1 if d2() throws and exception
=> _items = (d1, d2(d1));
public void Dispose()
{
if (!_disposed)
{
// dispose d1, d2, handle exception
_disposed = true;
}
}
}
d2
是一个函子,以便您可以链接一次性物品的构造:
using(var container = new DisposableTupleContainer(
new SqlCommand(someSelectQuery, conn, transaction),
c => c.ExecuteReader()))
{
// container.Item2 is your reader
}
此选项使您可以进行强键入。这与您现在拥有的东西相似。不过,我认为它不是很优雅:),带有工厂方法的选项或仅嵌套using
对我来说似乎更常见。
请注意,C#8包含improvements至using
,现在您可以在声明时指定它:
using var cmd = new SqlCommand(someSelectQuery, conn, transaction);
using var reader = cmd.ExecuteReader();