IDisposable metaphor in Java?

后端 未结 6 1197
滥情空心
滥情空心 2021-02-19 13:44

As a java developer getting into .NET I\'d like to understand the IDisposable interface. Could somebody please try to explain this and how it differs from what happens in Java?

6条回答
  •  鱼传尺愫
    2021-02-19 14:11

    There're situations when you need reliable disposal for resources owned by your class. E.g., opened connection should be closed in proper time, not when GC decides to collect memory. In .NET method Dispose is used by convention for this. It can be called in try ... finally block, e.g.:

    IConnection conn = OpenConnection();
    try{
       ...
    }finally{
        conn.Dispose();
    }
    

    Because this pattern is so widely used, there's a syntactic sugar for this:

    using(IConnection conn = OpenConnection()){
    } // Dispose is called at the end.
    

    As this syntax is very concise, sometimes it's useful to implement IDisposable on objects that don't own resources, but need some operation be executed at the end of its usage. E.g. consider class

    class TimeMeasure: IDisposable{
         public void Measure(string operation) { ... } // recourds operation time
         public void Dispose(){
            ... // print timings for all operations
         }
    }
    

    Usage:

    using(TimeMeasure m = new TimeMeasure())
    {
        DoFoo();
        m.Measure("Foo");
        DoBar();
        m.Measure("Bar");
    } // timings for 'Foo' and 'Bar' are printed here
    

    In Java more or less equivalent interface is Closeable. But there's no simple syntax to ensure its calls.

    How IDisposable should be implemented? This is a bit tricky:

    • if you own resources, you need to ensure they can be freed by explicit Dispose call or by GC but not by both. So, you need a flag indicating fact of disposal. For less code duplication, the disposal code is moved to separate method.

    Example:

    bool disposed;
    public void Dispose(){
        Dispose(true);
        GC.SuppressFinalize(this); // tell GC not to call Finalizer() for this object
    }
    
    ~MyObject(){
        Dispose(false);
    }
    
    void Dispose(bool manualDisposing){
        if(!disposed){
            disposed = true;
            if(manualDisposing)
               ... // call Dispose on all IDisposable fields
            ... // dispose all native resources
        }
    }
    
    • if you are not holding resources, as in case of TimeMeasure class, no need for Finalizer, you just do necessary logic in Dispose.

提交回复
热议问题