我正在尝试创建一个处理实现IDisposable的对象的通用方法,称为DisposeObject()
为了确保我处理原始引用指向的对象,我试图通过引用传递一个对象。
但是我收到的编译错误是
'ref'参数类型与参数类型
不匹配
在下面(简化)的代码中,_Baz
和_Bar
都实施IDisposable。
所以问题是,
[UPDATE]
从目前为止提供的答案,只要我没有将IDisposable参数设置为null,我就可以简单地按值传递一个对象而不使用ref
。
我现在还有另一个麻烦,是否在null
方法内将一次性对象设置为DisposeObject
。
以下是完整性的完整来源:
public class Foo : IDisposable
{
private Bar _Bar;
private Baz _Baz;
private bool _IsDisposed;
~Foo() { Dispose(false); }
public void Dispose(bool disposing)
{
if (!_IsDisposed)
{
if (disposing)
{
DisposeObject(ref _Baz);
DisposeObject(ref _Bar);
}
}
_IsDisposed = true;
}
private void DisposeObject(ref IDisposable obj)
{
try
{
if (obj == null)
return;
obj.Dispose();
obj = null;
} catch (ObjectDisposedException) { /* Already Disposed... */ }
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
public class Bar : IDisposable
{
public void Dispose() {}
}
public class Baz : IDisposable
{
public void Dispose() {}
}
[结果]
我在obj = null;
中删除了将参数设置为null(DisposeObject
)的代码
所以最终的代码变成了。
public void Dispose(bool disposing)
{
if (!_IsDisposed)
{
if (disposing)
{
DisposeObject(_Baz);
DisposeObject(_Bar);
}
}
_IsDisposed = true;
}
private void DisposeObject(IDisposable obj)
{
try
{
if (obj == null)
return;
obj.Dispose();
} catch (ObjectDisposedException) { /* Already Disposed... */ }
}
答案 0 :(得分:5)
这是您的示例的一个选项(目前无法针对编译器进行验证,但您会明白这一点):
private void DisposeObject<T>(ref T obj) where T : IDisposable
{
// same implementation
}
要拨打电话,请使用
DisposeObject<Baz>(ref _Baz);
DisposeObject<Bar>(ref _Bar);
正如其他注释中所指出的,你得到的编译器错误有其自己的目的(阻止你在方法中分配一些其他类型的IDisposable,导致状态不一致)。
答案 1 :(得分:4)
试试这个:
IDisposable d = (IDisposable)_Baz;
DisposeObject(ref d);
修改强>: 正如Adam指出的那样,您的代码不需要这样做。对象总是作为引用传递。
答案 2 :(得分:4)
当您传递引用类型时,无需通过引用传递。您应该从方法定义中删除ref
关键字。这样做,你不应该有任何问题,虽然我不确定这比仅仅调用Dispose()
更有效或更清楚(除了你不必为明确的实现投射它的事实)这会对你进行null
检查。
修改强>
跳舞,虽然我希望围绕这个主题的讨论对你有所帮助,但你的原始意图似乎并不可行。为了传递ref
的内容,你不能传递一个类型不同于ref
参数所期望的类型的变量(换句话说,你不能传递一个声明为{的变量如果class
参数为interface
,{1}}或其他IDisposable
实施ref
。由于IDisposable
参数允许赋值传播回调用者,因此可以允许将不兼容的类型存储在变量中。
这里最好的选择是自己指定ref
,如果这就是你想要的。如果你想将null
检查和忽略异常封装到很好的函数中,但不幸的是,无论你如何对它进行切片,null
都不适合你。
答案 3 :(得分:2)
这种方法闻起来很有趣但我暂时忽略了这一点。
要解决您的问题,您需要使用“(IDisposable)”投射您传递的对象
我承认编译器和Jon Skeet的意愿。你需要一个实际的对象:
IDisposable _BazD = (IDisposable)_Baz;
DisposeObject(ref _BazD);
除了try / catch之外,我还会在DisposeObject()中添加一个空检查。与昂贵的异常捕获相比,“obj == null”将是一个快速简单的检查,如果同一个对象多次被击中,那么它就会被快速轻松地检查。嗯...那是一分钟之前的那个?没关系。
答案 4 :(得分:0)
谢谢Dan C.我还没有足够的代表添加评论,所以我必须添加这个作为答案。但是,Dan C对此解决方案完全赞同。
这是有效的代码:
public override void Dispose()
{
base.Dispose();
DisposeOf<UserTableAdapter>(ref userAdapter);
DisposeOf<ProductsTableAdapter>(ref productsAdapter);
if (connection != null)
{
if (connection.State == ConnectionState.Open)
{
connection.Close();
}
DisposeOf<SqlConnection>(ref connection);
}
}
private void DisposeOf<T>(ref T objectToDispose) where T : IDisposable
{
if (objectToDispose != null)
{
objectToDispose.Dispose();
objectToDispose = default(T);
}
}