代码之家  ›  专栏  ›  技术社区  ›  Jerod Houghtelling

处理可标识对象的泛型函数

  •  11
  • Jerod Houghtelling  · 技术社区  · 15 年前

    我正在开发一个处理大量Sql对象的类—Connection、Command、DataAdapter、CommandBuilder等。有多个实例的代码如下:

    if( command != null )
    {
        command.Dispose();
    }
    
    if( dataAdapter != null )
    {
        dataAdapter.Dispose();
    }
    
    etc
    

    if( command != null )
    {
        command.Dispose();
        command = null;
    }
    

    private void DisposeObject<TDisposable>( ref TDisposable disposableObject )
        where TDisposable : class, IDisposable
    {
        if( disposableObject != null )
        {
            disposableObject.Dispose();
            disposableObject = null;
        }
    }
    

    我的问题是。。。

    1. 这个泛型函数是个坏主意吗?
    2. 是否需要将对象设置为 null ?

    我知道 using 语句,但是我不能总是使用它,因为我有一些成员变量需要在一次调用之后保持更长的时间。例如连接和事务对象。

    10 回复  |  直到 15 年前
        1
  •  1
  •   Tim Robinson    15 年前

    我假设这些是字段而不是局部变量,因此 using

    这个泛型函数是个坏主意吗?

    是否需要将对象设置为null?

    从技术上讲,一个对象应该允许多次调用它的 Dispose

    处置 方法,则未能将引用设置为null不会泄漏内存。相反,它是一个方便的防御双重处置。

        2
  •  7
  •   Mark Byers    15 年前

    你应该考虑一下是否可以使用 using 声明。

    using (SqlCommand command = ...)
    {
        // ...
    }
    

    这确保了 Dispose 当控件离开使用的范围时,在命令对象上调用。与您自己编写清理代码相比,这有许多优点:

    • 它更简洁。
    • 变量永远不会被设置为null—它在一个语句中声明和初始化。
    • 它是例外安全的。
    • 如果使用语句进行嵌套,那么资源自然会以正确的顺序(与创建它们的顺序相反)进行释放。

    通常不需要在使用完变量后将其设置为null。重要的是,在使用完资源后调用Dispose。如果使用上述模式,不仅不需要将变量设置为null,而且会产生编译错误:

    Cannot assign to 'c' because it is a 'using variable'
    

    需要注意的是 只有在同一方法调用中获取和释放对象时才有效。如果资源需要在多个方法调用期间保持活动状态,则不能使用此模式。在这种情况下,您可能需要实现类 IDisposable null 在这种情况下没有错,但这并不重要,因为垃圾收集器无论如何都会正确地清理内存。重要的是确保在调用dispose方法时释放您拥有的所有资源,并且您正在这样做。

    • 您应该确保如果Dispose被调用两次,它不会抛出异常。您的实用程序函数可以正确处理此情况。
    • 您应该确保对象上的相关方法引发 ObjectDisposedException
        3
  •  6
  •   Stephen Cleary    15 年前

    你应该实施 IDisposable my blog post 关于这个问题。如果这样做不好,那么类就没有遵循OOP原则,需要重构。

    它是 not necessary null 在处理它们之后。

        4
  •  3
  •   Frank Schwieterman    15 年前

    如果对象有很多清理工作要做,它们可能希望在单独的一次性物品列表中跟踪需要删除的内容,并一次处理所有这些内容。然后在teardown中,它不需要记住所有需要处理的内容(也不需要检查null,它只是在列表中查找)。

    public class RecycleBin : IDisposable
    {
        private List<IDisposable> _toDispose = new List<IDisposable>();
    
        public void RememberToDispose(IDisposable disposable)
        {
            _toDispose.Add(disposable);
        }
    
        public void Dispose()
        {
            foreach(var d in _toDispose)
                d.Dispose();
    
            _toDispose.Clear();
        }
    }
    
        5
  •  1
  •   James Curran    15 年前

    我假设您在一个方法中创建资源,在另一个方法中处理它,并在一个或多个其他方法中使用它,使 using

    在这种情况下,你的方法很好。

    大多数对象都有一个资源——内存,垃圾收集负责释放内存,所以我们不必担心它。有些还拥有其他资源:文件句柄、数据库连接等。对于第二类,我们必须实现IDisposable,以释放其他资源。

    一旦调用Dispose方法,这两个类别将保持相同:它们持有内存。在这种情况下,我们可以让变量超出作用域,删除对内存的引用,并允许GC最终释放它——或者我们可以通过将变量设置为null,并显式删除对内存的引用来强制解决问题。我们仍然要等到GC启动后才能真正释放内存,而且变量很可能会超出作用域,在设置为null的瞬间之后,所以在绝大多数情况下,它根本没有效果,但在少数情况下,它会允许内存提前几秒钟释放。

    但是,如果您的具体情况是检查null以确定是否应该调用Dispose,那么 如果有可能调用Dispose()两次,请将其设置为null。

        6
  •  1
  •   supercat    15 年前

    考虑到iDisposable不包括任何确定对象是否已被释放的标准方法,我喜欢在释放对象时将其设置为null。当然,处理一个已经被处理的对象是无害的,但是能够在监视窗口中检查一个对象并一眼就知道哪些字段已经被处理是很好的。能够进行代码测试也很好,以确保应该被释放的对象是(假设代码在释放变量时遵守将变量置零的约定,而不是在其他时间)。

        7
  •  0
  •   STO    15 年前
        8
  •  0
  •   JSBÕ±Õ¸Õ£Õ¹    15 年前

    其他人建议 using 构造,我也建议。但是,我想指出的是,即使您确实需要一个实用方法,也完全没有必要像您所做的那样将其泛化。只需声明您的方法 IDisposable :

    private static void DisposeObject( ref IDisposable disposableObject )
    {
        if( disposableObject != null )
        {
            disposableObject.Dispose();
            disposableObject = null;
        }
    }
    
        9
  •  0
  •   Christian Hayter    15 年前

    您不需要将变量设置为 null . 我的意思是 IDisposable.Dispose 就是让对象进入一种状态,这样它就可以在内存中无害地挂起,直到GC完成它,所以您只需“处理并忘记”。

    using 声明。在一个方法中创建一个对象,然后在另一个方法中处理它是一个复杂的过程 真正地

    using(var xxx = whatever()) {
        LotsOfProcessing(xxx);
        EvenMoreProcessing(xxx);
        NowUseItAgain(xxx);
    }
    

    我确信这有一个标准的模式名称,但我只是称之为“摧毁你所创造的一切,但没有别的”。

        10
  •  0
  •   Community Mohan Dere    8 年前
    推荐文章