Is there any benefit to implementing IDisposable on classes which do not have resources?

后端 未结 11 2078
挽巷
挽巷 2020-12-14 05:14

In C#, if a class, such as a manager class, does not have resources, is there any benefit to having it : IDisposable?

Simple example:

pu         


        
相关标签:
11条回答
  • 2020-12-14 06:12

    While your code wouldn't benefit from implementing IDisposable, I can't agree with other opinions here that state that IDisposable is only meant to (directly or indirectly) free native resources. IDisposable can be used whenever the object needs to perform clean up task at the end of it's lifetime span. It's extremely useful together with using.

    A very popular example: in ASP.NET MVC Html.BeginForm returns an IDisposable. On creation, the object opens the tag, when Dispose is called it closes it. No native resources involved, yet still a good use of IDisposable.

    0 讨论(0)
  • 2020-12-14 06:12

    There one more reason that no one mentioned (though it's debateful if it really worth it): The convension says that if someone uses a class that implement IDisposable, it must call its Dispose method (either explicitly or via the 'using' statement). But what happens if V1 of a class (in your public API) didn't need IDisposable, but V2 does? Technically it doesn't break backward compatibility to add an interface to a class, but because of that convension, it is! Because old clients of your code won't call its Dispose method and may cause resources to not get freed. The (almost) only way to avoid it is to implement IDisposable in any case you suspect that you'll need it in the future, to make sure that your clients always call your Dispose method, that some day may be really needed. The other (and probably better) way is to implemet the lambda pattern mentioned by JaredPar above in the V2 of the API.

    0 讨论(0)
  • 2020-12-14 06:14

    IDisposable is also great if you want to benefit the using () {} syntax.

    In a WPF project with ViewModels, I wanted to be able to temporarily disable NotifyPropertyChange events from raising. To be sure other developers will re-enable notifications, I wrote a bit of code to be able to write something like:

    using (this.PreventNotifyPropertyChanges()) {
        // in this block NotifyPropertyChanged won't be called when changing a property value
    }
    

    The syntax looks okay and is easily readable. For it to work, there's a bit of code to write. You will need a simple Disposable object and counter.

    public class MyViewModel {
        private volatile int notifyPropertylocks = 0; // number of locks
    
        protected void NotifyPropertyChanged(string propertyName) {
            if (this.notifyPropertylocks == 0) { // check the counter
                this.NotifyPropertyChanged(...);
            }
        }
    
        protected IDisposable PreventNotifyPropertyChanges() {
            return new PropertyChangeLock(this);
        }
    
        public class PropertyChangeLock : IDisposable {
            MyViewModel vm;
    
            // creating this object will increment the lock counter
            public PropertyChangeLock(MyViewModel vm) {
                this.vm = vm;
                this.vm.notifyPropertylocks += 1;
            }
    
            // disposing this object will decrement the lock counter
            public void Dispose() {
                if (this.vm != null) {
                    this.vm.notifyPropertylocks -= 1;
                    this.vm = null;
                }
            }
        }
    }
    

    There are no resources to dispose here. I wanted a clean code with a kind of try/finally syntax. The using keyword looks better.

    0 讨论(0)
  • 2020-12-14 06:15

    One major point of confusion, which may not be applicable in your case but arises often, is what exactly constitutes a "resource". From the perspective of an object, an unmanaged resource is something which an outside entity () is "doing"(*) on its behalf, which that outside entity will keep doing--to the detriment of other entitites--until told to stop. For example, if an object opens a file, the machine which hosts the file may grant that object exclusive access, denying everyone else in the universe a chance to use it unless or until it gets notified that the exclusive access isn't needed anymore.

    (*) which could be anything, anywhere; possibly not even on the same computer.

    (**) or some way in which the the behavior or state of an outside entity is altered

    If an outside entity is doing something on behalf of an object which is abandoned and disappears without first letting the entity know its services are no longer required, the outside entity will have no way of knowing that it should stop acting on behalf of the object which no longer exists. IDisposable provides one way of avoiding this problem by providing a standard means of notifying objects when their services are not required. An object whose services are no longer required will generally not need to ask any further favors from any other entities, and will thus be able to request that any entities that had been acting on its behalf should stop doing so.

    To allow for the case where an object gets abandoned without IDisposable.Dispose() having been called first, the system allows objects to register a "failsafe" cleanup method called Finalize(). Because for whatever reason, the creators of C# don't like the term Finalize(), the language requires the use of a construct called a "destructor" which does much the same thing. Note that in general, Finalize() will mask rather than solve problems, and can create problems of its own, so it should be used with extreme caution if at all.

    A "managed resource" is typically a name given to an object which implements IDisposable and usually, though not always, implements a finalizer.

    0 讨论(0)
  • 2020-12-14 06:19

    Short answer would be no. However, you can smartly use the nature of the Dispose() executement at the end of the object lifecycle. One have already gave a nice MVC example (Html.BeginForm)

    I would like to point out one important aspect of IDisposable and using() {} statement. At the end of the Using statement Dispose() method is automatically called on the using context object (it must have implemented IDisposable interface, of course).

    0 讨论(0)
提交回复
热议问题