0

I've seen similar questions, but the answers don't seem to answer what IDispose really should do.

So far, I have a class that looks like this:

public class ArrayPointsEnumerator : IEnumerator<Vector3Int> {

    Vector3Int max;
    public ArrayPointsEnumerator(Vector3Int size) {
        max = size - Vector3Int.one;
    }

    Vector3Int point = Vector3Int.zero;
    public Vector3Int Current  => point;
    object IEnumerator.Current => point;


    public bool MoveNext() {

        // (same functionality as:) // // // // //
        // for(int x = 0; x < max.x + 1; x++)   //
        //  for(int y = 0; y < max.y + 1; y++)  //
        //   for(int z = 0; z < max.z + 1; z++) //

        if(point.z < max.z) point.z++;
        else {
            point.z = 0;
            if(point.y < max.y) point.y++;
            else {
                point.y = 0;
                if(point.x < max.x) point.x++;
                else return false;
            }
        }

        return true;

    }

    public void Reset() => point = Vector3Int.zero;

}

Which is meant to be used like this:

ClassWithArray {
    object[,,] array;
    Vector3Int Size => /*array.GetLength(0 through 2)*/;
    public ArrayPointsEnumerator ArrayPoints => ArrayPointsEnumerator(Size);
}

 ...

foreach(Vector3Int point in ClassWithArray.ArrayPoints {
    //do stuff
}

But it's missing an IDispose method, which Visual Studio is giving me two solutions for.


(Both of these are the unedited "quick fixes" Visual Studio provies.)


Implement interface.

public void Dispose() {
    throw new NotImplementedException();
}


Implement interface with Dispose pattern.

private bool disposedValue = false; // To detect redundant calls

protected virtual void Dispose(bool disposing) {
    if(!disposedValue) {
        if(disposing) {
            // TODO: dispose managed state (managed objects).
        }

        // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
        // TODO: set large fields to null.

        disposedValue = true;
    }
}

// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~ArrayPointsEnumerator()
// {
//   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
//   Dispose(false);
// }

// This code added to correctly implement the disposable pattern.
public void Dispose() {
    // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
    Dispose(true);
    // TODO: uncomment the following line if the finalizer is overridden above.
    // GC.SuppressFinalize(this);
}



And honestly, maybe I'm just being really dumb here, but even after looking at the Microsoft Docs for Implementing a Dispose method and IDisposable Interface I'm confused on what Dispose() should do. I've also read answers to similar questions, (again maybe I'm just being dumb or just missing something) but they don't seem to explain what Dispose() is.

Grant Shotwell
  • 330
  • 3
  • 14
  • From the docs: `"Provides a mechanism for releasing unmanaged resources."` What specifically are you not sure about or have a question about? – Igor Oct 01 '19 at 19:17
  • It is not clear from your code why you need disposable. In general it is used to release unmanaged resources (allocated by OS or external components) in predictable manner: https://www.oreilly.com/library/view/programming-c/0596001177/ch04s04.html – Nicklaus Brain Oct 01 '19 at 19:19
  • Mostly taught myself how to code, so no idea what 'realeasing unmanaged resources' means. Is it just deleting itself after it's done? – Grant Shotwell Oct 01 '19 at 19:20
  • 1
    If you look at the docs for [`IEnumerator`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerator-1?view=netframework-4.8) you can see an example implementation where the implementation of `void Dispose()` is nothing more than an empty method because the implementation has nothing that needs to be explicitly released (just like your code). – Igor Oct 01 '19 at 19:20
  • 1
    @NicklausBrain The `IEnumerator` interface requires the method have an implementation. The OP is asking what this method is supposed to do so he can provide an implementation. –  Oct 01 '19 at 19:20
  • Here's some good reading which will help you understand what disposing is and why we do it. https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/memory-management-and-gc and https://stackoverflow.com/questions/3607213/what-is-meant-by-managed-vs-unmanaged-resources-in-net – Joas Oct 01 '19 at 19:22
  • 2
    Ok, so the real question is what are unmanaged resources and how (in your Dispose implementation) would you release them? – Igor Oct 01 '19 at 19:22
  • 1
    @Igor ^ yes, thank you – Grant Shotwell Oct 01 '19 at 19:23
  • Possible duplicate of [Proper use of the IDisposable interface](https://stackoverflow.com/q/538060/1260204) ? ← Does that answer address your question as well? – Igor Oct 01 '19 at 19:24
  • 3
    See marked duplicates. Short version: if you implement `IEnumerator`, you have to implement `IDisposable` as well because of the interface declaration. But there's no requirement that your `IDisposable.Dispose()` method actually _do_ anything. If you don't have anything to dispose, then don't dispose anything. Beyond that I will suggest that one almost never needs to implement `IEnumerator` explicitly anyway; write an iterator method, let the compiler do the work for you. You can include `using` as necessary to ensure disposing resources if needed. – Peter Duniho Oct 01 '19 at 19:30
  • Alright, thanks everyone. It seems like I was confused because I've yet to use an "unmanaged resource". So in this case, `Dispose` should do nothing. – Grant Shotwell Oct 01 '19 at 19:34

1 Answers1

1

Maybe you're confused just by because there is nothing obvious to Dispose in your code ?

Dispose is here to release unmanaged resources, like (for example) external data connections, file handlers, etc. You don't seem to have such things.

If your code consumes something that is implementing itself IDisposable, simply call Dispose on it (with the required try/catch/finally)

You could also put to "null" some of your fields but it's not useful or recommended, the GC is here for this.

If you don't need to Dispose anything, just do not introduce IDisposable. If it's introduced by another interface that you can't remove, just leave the implementation of Dispose() empty (with a comment, for future reference).

AFract
  • 8,868
  • 6
  • 48
  • 70