There are many examples of the implementation of the Dispose pattern in relation to the wrappers for the C ++ DLL, but they all differ slightly, it seems that many simply reprint the pattern from a favorite source and that's it.
There is a DLL from which one single function is called, the code is as follows:
public class U2KApi:IDisposable { private const string FunctionName = "fname"; private const string B5 = "param1"; private const int B6 = param2; public delegate int MainFuncDelegate(int b1, int b2, int b3, int b4, string b5, int b6); private bool _disposedValue; private SafeLibraryHandle _safeLibraryHandle; private MainFuncDelegate _mainFuncDelegate; public U2KApi() { var fileName = "dllname.dll"; _safeLibraryHandle = Kernel32Dll.LoadLibrary(fileName); if (_safeLibraryHandle.IsInvalid) { var hrForLastWin32Error = Marshal.GetHRForLastWin32Error(); Marshal.ThrowExceptionForHR(hrForLastWin32Error); } var procAddress = Kernel32Dll.GetProcAddress(_safeLibraryHandle, FunctionName); if (procAddress == IntPtr.Zero) { _safeLibraryHandle.Close(); throw new ArgumentException(); } var delegateForFunctionPointer = Marshal.GetDelegateForFunctionPointer<MainFuncDelegate>(procAddress); _mainFuncDelegate = delegateForFunctionPointer; } public int MainFunc(int b1, int b2, int b3, int b4) { return _mainFuncDelegate(b1, b2, b3, b4, B5, B6); } private void Dispose(bool disposing) { if (_disposedValue) return; if (disposing) { if (_safeLibraryHandle != null) { if (!_safeLibraryHandle.IsClosed) { _safeLibraryHandle.Close(); } } } _safeLibraryHandle = null; _mainFuncDelegate = null; _disposedValue = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~U2KApi() { Dispose(false); } } static class Kernel32Dll { [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern SafeLibraryHandle LoadLibrary(string fileName); [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] public static extern IntPtr GetProcAddress(SafeLibraryHandle hModule, string procname); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool FreeLibrary(IntPtr hModule); } class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid { private SafeLibraryHandle() : base(true) { } protected override bool ReleaseHandle() { return Kernel32Dll.FreeLibrary(handle); } } Questions about the following:
- Whether it is necessary to close
SafeHandleinside if (disposing) - I saw examples of the opposite, when the check on disposing went down, and, honestly, I do not understand how correctly. Why then make a fuss out ofDispose(bool)? - Do I need to assign null
_safeLibraryHandleand_mainFuncDelegate- memory will not eat much? - If not, can everything be simplified?
UPD. I read the answers VladD, tried to think. As I understand it, since the handle is wrapped in SafeHandleZeroOrMinusOneIsInvalid , everything can be reduced to a simple _safeLibraryHandle release in the usual Dispose (), throwing out the finalizer and the overloaded Dispose(bool) .