3

我正在尝试创建一个通用方法来处理实现IDisposable的对象,称为DisposeObject()

为了确保我正在处理由原始引用指向的对象,我试图通过引用传递一个对象。

但我收到一个编译错误,上面写着

'ref' 参数类型与参数类型不匹配

在下面的(简化的)代码中,两者都_Baz实现_BarIDisposable

替代文字

所以问题是,

  1. 为什么我会收到此错误?
  2. 有没有办法绕过它?

[更新] 从目前提供的答案来看,只要我不将 IDisposable 参数设置为 null,我就可以简单地按值传递对象,而无需使用ref. 我现在遇到了另一个麻烦,是否nullDisposeObject方法内设置一次性对象。

以下是完整性的完整来源:

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() {}
}

[结果]
我删除了将参数设置为 null ( obj = 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... */ }
    }
4

5 回答 5

7

这是您的示例的一个选项(现在无法针对编译器进行验证,但您会明白的):

private void DisposeObject<T>(ref T obj) where T : IDisposable
{
    // same implementation
}

要调用它,请使用

DisposeObject<Baz>(ref _Baz);
DisposeObject<Bar>(ref _Bar);

正如其他评论中所指出的,您得到的编译器错误有其自身的目的(防止您在方法中分配其他类型的 IDisposable,从而导致状态不一致)。

于 2009-04-27T16:24:21.950 回答
4

试试这个:

IDisposable d = (IDisposable)_Baz;
DisposeObject(ref d);

编辑:正如亚当指出的那样,您的代码不需要这是参考。对象总是作为引用传递。

于 2009-04-27T15:50:40.640 回答
4

您无需通过引用传递,因为您正在传递引用类型。您应该ref从方法定义中删除关键字。这样做,你不应该有任何问题,虽然我不确定这比简单调用更有效或更清晰Dispose()(除了你不必为显式实现强制转换它并且这会null检查你)。

编辑

跳舞,虽然我希望围绕这个主题的讨论对您有所帮助,但您的初衷似乎并不可行。为了传递一些 as ref,你不能传递一个类型不是ref参数期望的类型的变量(换句话说,你不能传递一个声明为 aclass或其他interface实现的变量,IDisposable如果ref参数是IDisposable)。因为ref参数允许赋值传播回调用者,您将打开允许不兼容类型存储在变量中的可能性。

null如果这是你想要的,你最好的选择是分配自己。如果您想将null检查和忽略异常封装到函数中,那很好,但ref不幸的是,无论您如何切片,在这种情况下都不会为您工作。

于 2009-04-27T15:55:18.337 回答
2

这种方法闻起来很有趣,但我暂时忽略它。

要解决您的问题,您需要使用“(IDisposable)”转换您传递的对象

我承认编译器和 Jon Skeet 的意愿。为此,您需要一个实际对象:

IDisposable _BazD = (IDisposable)_Baz;
DisposeObject(ref _BazD);

除了 try/catch 之外,我还会在 DisposeObject() 中添加一个空检查。与昂贵的异常捕获相比,“obj==null”将是一种快速简便的检查,如果同一对象多次命中该异常捕获。 嗯……那是一分钟前吗?没关系。

于 2009-04-27T15:51:09.347 回答
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);
    }
}
于 2010-05-13T19:42:41.387 回答