0

I have a class as follows:

public class WowRedirectionDisabler : IDisposable
{
    private IntPtr _oldValue;
    private bool _isDisposed;
        
    public WowRedirectionDisabler ()
    {
        if (!Environment.Is64BitOperatingSystem)
            throw new NotSupportedException("OperatingSystem must be 64 bits");

        if (!NativeMethods.Wow64DisableWow64FsRedirection(out _oldValue))
            throw new ExternalException("Unable to disable Wow64 Redirection");
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_isDisposed) return;

        if (!NativeMethods.Wow64RevertWow64FsRedirection(_oldValue))
            throw new ExternalException("Unable to revert Wow64 Redirection");
    }

    ~WowRedirectionDisabler ()
    {
        Dispose(false);
    }
}

Can I guarantee that _oldValue will always exist in case the finaliser needs to run? If not, how to implement this properly?

computeka
  • 15
  • 5
  • 8
    I don't understand the question. Can you be sure that a private field of your class will be there at the point of finalization? Yes. You should, however, *not* throw exceptions from `Dispose`, and you should set `_isDisposed` to true. – GSerg Sep 30 '20 at 13:39
  • @GSerg Yeah pretty much that. I mean my logic was ... because of the nondeterministic nature of the GC you can't guarantee that managed resources haven't already been disposed when the finalizer is called, so how's it any different for something like a private IntPtr field? – computeka Sep 30 '20 at 13:42
  • @GSerg forgot setting _isDisposed. But not really sure what to do if not throw in this case, being unable to restore previous state is a fatal exception and execution should not continue (for my usage case). – computeka Sep 30 '20 at 13:43
  • I think you are confusing disposal and destruction. You are in control of what disposing means. You are never to worry that you might be dealing with a partially *desctructed* object. And you protect yourself from double-disposing by setting `_isDisposed` to true. – GSerg Sep 30 '20 at 13:45
  • 1
    @CameronTinker I find https://stackoverflow.com/a/898867/11683 a much more readable version... – GSerg Sep 30 '20 at 13:46
  • @GSerg the comment about disposal vs destruction and how you never have to deal with a partially destructed object does clarify things. And while I understand why it's not a good idea to throw on Dispose, I also don't know how else to implement this - if the redirection cannot be reverted that shouldn't be swept under the rug and it should signify a fatal exception and (controlled) termination of the application. – computeka Sep 30 '20 at 13:54
  • @computeka If you miss a `using`, Dispose will be called by GC, in which case you [won't](https://stackoverflow.com/a/1538659/11683) be able to have a controlled termination. Arguably, then just call [`Environment.FailFast`](https://learn.microsoft.com/en-us/dotnet/api/system.environment.failfast?view=netcore-3.1) instead on throwing the exception. – GSerg Sep 30 '20 at 14:16

0 Answers0