It's a good practice. The below is taken from here
For the majority of the objects that your app creates, you can rely on
the .NET Framework's garbage collector to handle memory management.
However, when you create objects that include unmanaged resources,
you must explicitly release those resources when you finish using them
in your app. The most common types of unmanaged resource are objects
that wrap operating system resources, such as files, windows, network
connections, or database connections.
Although the garbage collector is able to track the lifetime of an
object that encapsulates an unmanaged resource, it doesn't know how to
release and clean up the unmanaged resource.
If your types use unmanaged resources, you should do the following:
Implement the dispose pattern. This requires that you provide an IDisposable.Dispose implementation to enable the deterministic release
of unmanaged resources. A consumer of your type calls Dispose when the
object (and the resources it uses) is no longer needed. The Dispose
method immediately releases the unmanaged resources.
Provide for your unmanaged resources to be released in the event that a consumer of your type forgets to call Dispose.
There are two ways to acheive option 2 above:
Use a safe handle to wrap your unmanaged resource. This is the recommended technique. Safe handles are derived from the
System.Runtime.InteropServices.SafeHandle class and include a robust
Finalize method. When you use a safe handle, you simply implement the
IDisposable interface and call your safe handle's Dispose method in
your IDisposable.Dispose implementation. The safe handle's finalizer
is called automatically by the garbage collector if its Dispose method
is not called.
Override the Object.Finalize method. Finalization enables the non-deterministic release of unmanaged resources when the consumer of
a type fails to call IDisposable.Dispose to dispose of them
deterministically. However, because object finalization can be a
complex and error-prone operation, we recommend that you use a safe
handle instead of providing your own finalizer.