0

I've got a generic class that starts with:

public class EntityContextFactory<T>
    where T: class, IDisposable, IObjectContextAdapter, new()

Later in the class when I have a method that contains:

            T context = HttpContext.Current.Items[objectContextKey] as T;
            if (context != null)
            {
                context.Dispose();
                GC.SuppressFinalize(context);
                HttpContext.Current.Items.Remove(objectContextKey);
            }

I get a warning from ReSharper that says GC.SuppressFinalize is invoked on a type without destructor. How can I remove this error? I know Dbcontexts do have a destructor because when I write this type of class non generically, I get no such error. I tried declaring that T implements the same interfaces as a Dbcontext but that didn't seem to work...

SventoryMang
  • 10,275
  • 15
  • 70
  • 113

3 Answers3

4

You can remove this error by not calling SuppressFinalize. There is no generic constraint (and presumably no ReSharper constraint) you could apply to require a finalizer.

Any class that has a finalizer should be calling GC.SuppressFinalize(this); in its Dispose. If the class does not do so, it probably has a good reason and you shouldn't be calling it either.

Gideon Engelberth
  • 6,095
  • 1
  • 21
  • 22
  • +1 - its the `Dispose()` method that should call `GC.SuppressFinalize()` – BrokenGlass Jan 18 '12 at 17:25
  • Quite right sir, didn't think to check that but after looking into decompiled code for a DbContext the Dispose method does indeed call Gc.SuppressFinalize(this). – SventoryMang Jan 18 '12 at 17:26
1

First, GC.SuppressFinalize(obj) checks, whether the given reference is reference equal to the this-pointer of the directly calling method (see online help: "The obj parameter is required to be the caller of this method.") - so any call other than GC.SuppressFinalize(this) will throw an exception!

Second, calling GC.SuppressFinalize(this) indicates the GC NOT to run finalization code (the instance is removed from the finalization queue). The shorter the finalization queue, the faster the garbage collector runs... but as all objects inherit a finalizer...

Third, calling GC.SuppressFinalize(this) will effectively prevent any destructor from running. I personally consider destructors a code smell! Writing correct finalizer code is anything but trivial (remember, all references could have gone... (freed already)). Besides that, dealing with unmanaged resources should be done implementing IDisposable correctly and calling Dispose() BEFORE the object gets collected. Having a finalizer is only the last line of defense - when no one has called Dispose(). Usually one should use constructs like using() - which will take care of calling Dispose().

For a detailed explanation of the subject see Proper use of the IDisposable interface

So - make the call at all - and if - where to place the call? Make the call, if You don't handle unmanaged resources and therefore have no destructor. Common place is inside Dispose() - but that's not required. Another favourite of mine is .ctor() - although the this reference isn't fully constructed yet...

The ReSharper warning is a bit misleading here. It appears in two situations - when the argument is not the caller and when the call isn't in Dispose(). In Your particular case, You should not make the call.

Community
  • 1
  • 1
Martin
  • 11
  • 1
1

Description

I am not sure if you need to GC.SuppressFinalize. Usually this would used for Unmanaged Resources. The Garbage Collector (GC) does that for managed resources without GC.SuppressFinalize. The DbContext is a managed resource and you should Dispose() that instead of calling GC.SuppressFinalize.

You should prevent users of your application from calling an object's Finalize method directly by limiting its scope to protected.

You can read When should I use GC.SuppressFinalize()? and When and How to Use Dispose and Finalize in C#

More Information

Community
  • 1
  • 1
dknaack
  • 60,192
  • 27
  • 155
  • 202
  • Thanks, though in your sample that would do nothing as EntityContextFactory is a generic abstract class and not what I am trying to make sure has a deconstructor. – SventoryMang Jan 18 '12 at 17:28
  • I updated my answer in the same moment you wrote your comment. It is right. The point is that the DbContext is a managed resource, so Dispose instead of SuppressFinalize is the right way. – dknaack Jan 18 '12 at 17:31