C# 如果对象是IDisposable类的字段,是否应该将其标记为只读

C# 如果对象是IDisposable类的字段,是否应该将其标记为只读,c#,idisposable,C#,Idisposable,问题描述: 我有一个实现IDisposable的类(FooClass),它将另一个一次性类(OtherDisposableClass)作为其构造函数的参数 我创建了OtherDisposableClass的一个实例 我创建一个FooClass实例,并将实例OtherDisposableClass传递给它 OtherDisposableClass的实例不应该是可变的,所以我将其标记为只读 我无法在Dispose方法中删除对OtherDisposableClass实例的引用 问题 在这里做什么最好?

问题描述:

  • 我有一个实现IDisposable的类(FooClass),它将另一个一次性类(OtherDisposableClass)作为其构造函数的参数
  • 我创建了OtherDisposableClass的一个实例
  • 我创建一个FooClass实例,并将实例OtherDisposableClass传递给它
  • OtherDisposableClass的实例不应该是可变的,所以我将其标记为只读
  • 我无法在Dispose方法中删除对OtherDisposableClass实例的引用
  • 问题

    在这里做什么最好?我们应该吗

  • 不要将OtherDisposableClass的实例标记为只读,以便在Dispose方法中将其设置为“null”
  • 将OtherDisposableClass标记为只读,并且不再删除对它的引用
  • 别的
  • 请详细说明你的答案。多谢各位

    public class FooClass : IDisposable
    {
        private readonly OtherDisposableClass _disposable;
        private readonly string _imageSource;
        private readonly string _action;
        private readonly string _destination;
    
        private bool _isInitialized;
    
        public FooClass(OtherDisposableClass disposable)
        {
            _disposable = disposable;
        }
        ~FooClass() 
        {
            // Finalizer calls Dispose(false)
            Dispose(false);
        }
    
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        protected virtual void Dispose(bool disposing)
        {
            // Not possible because _disposable is marked readonly
            _disposable = null;
        }
    }
    

    创建
    OtherDisposableClass
    的事情应该是处理它。。。把它放在
    FooClass
    中(如果您愿意,您可以将其设置为
    只读

    将其设置为null无论如何都不会有任何效果,它只会将FooClass内的引用设置为null(无论如何都将被释放)

    编辑

    从给出的代码来看,您甚至不需要在这里实现IDisposable——这只是让事情变得过于复杂。如果在
    FooClass
    的构造函数中创建了
    OtherDisposableClass
    的实例,则可以实现IDisposable,只需在
    FooClass.Dispose()中调用
    OtherDisposableClass.Dispose()


    这里创建的FooClass依赖于OtherFooClass-OtherFooClass将超过FooClass-因此FooClass应该先被GC'd,然后剩下的OtherDisposableClass将没有引用-这将允许它在VB.NET中被GC'd

    ,如果实现了
    IDisposable
    的类型有任何变量是用events
    声明的
    ,通常最好在
    Dispose
    方法中将这些变量设置为
    null
    ,因为不这样做将意味着这些变量所引用的对象将保留对已处理对象的引用。在许多短期对象订阅来自长期对象的事件的情况下,这可能会导致严重的内存泄漏

    尽管C#不允许VB.NET风格的
    带有事件
    声明,但可以在C#中对行为类似的属性进行编码:

    // Handle a property Wobbler which identifies an object whose Wibbled event
    // I want to handle with my WibbleWobble method.
    Woozle _wobble;
    Woozle Wobbler {
      get { return _wobbler; }
      set {
        var wasWobbler = _wobbler
        if (wasWobbler == value) return; // Don't unsubcribe and resubscribe same object
        if (wasWobbler != null)
          wasWobbler.Wibbled -= WibbleWobble; // Unsubscribe old event
        if (value != null)
          value.Wibbled += WibbleWobble; // Subscribe new event
        _wobbler = value;
      }
    };
    
    如果使用这样的模式(这是确保订阅与取消订阅配对的好方法),则应在
    Dispose
    方法中将
    Wobbler
    设置为
    null
    ,以确保附加到它的任何事件都被分离

    除上述场景外,
    Dispose
    是否将内容设置为
    null
    ,通常无关紧要,因为处理这些字段引用的对象时,唯一应该做的事情就是处理它们并取消它们的事件,在编码良好的对象上多次调用
    Dispose
    ,应该是无害的。但是,在一些情况下,在dispose中将字段设置为
    null
    可能会有所帮助。一些集合使用数组存储数据,并指示哪些插槽包含有意义的数据;如果集合通过指示插槽不包含任何有意义的内容而从数组中“删除”了一个项,但没有使引用无效,则GC将保持该项以及它包含直接或间接引用的任何内容处于活动状态。如果已处理的对象使其对其他对象的引用无效,则集合保持活动状态的数据量可能会最小化


    顺便说一句,请注意,上面的代码不是线程安全的,即使订阅/取消订阅方法是线程安全的,并且只使用通过
    联锁的
    方法访问
    \u-wobbler
    ,也不能在没有锁定的情况下非常干净地实现线程安全。如果
    \u wobbler
    在处理订阅/取消订阅之前被更新,那么如果
    wobbler
    在一个线程中发送给某个对象,在另一个线程中发送给另一个对象,则第二个线程可能会在第一个线程发送其订阅请求之前向George发送取消订阅请求(导致订阅悬空)。如果在处理订阅/取消订阅之前未对其进行更新,则两次同时尝试将摆动器设置为George可能会导致George收到两个连续的订阅请求(这最终可能导致挂起订阅).

    IDisposable
    界面允许您以确定的方式释放非托管资源。非托管资源可以是文件句柄、数据库连接等。处置对象不会释放任何内存。内存仅由垃圾收集器回收,您几乎无法控制何时以及如何回收处理对象不会释放任何内存

    垃圾收集和IDisposable之间仍然有联系。如果您的类直接控制非托管资源,则应在终结期间释放此资源。但是,在类上使用终结器会影响性能,如果可能,应该避免使用终结器
    FooClass
    不直接控制非托管资源,不需要终结器。但是,要强制非托管资源的确定性释放,重要的是
    FooClass.Dispose
    调用
    OtherDisposableClass.Dispose
    Dispose
    被明确调用时(当
    disposing
    true
    时)。如果从终结器调用了
    Dispose
    ,则不应调用其他托管对象上的方法,因为这些对象可能会