1

In the following code:

public sealed class Switch
{
    public static MyObj s_object = new MyObj();
    private readonly SomeObject m_object = new SomeObject();

    ~Switch()
    {
        m_object?.Dispose();
    }
}

public class Test()
{
    Test() 
    {
        Switch switch = new Switch();
        switch = null;
        ...
    }
}

When the Test ctor executes, a new Switch object is created then immediately set to null. At some point the GC will dispose of it, calling the ~Switch() destructor in the process. But will that happen when a class contains a static field like s_object and the calling app has not terminated (app domain still loaded)? Static objects persist for the lifetime of the application; does that mean the non-static class containing it will too?

Mgetz
  • 5,108
  • 2
  • 33
  • 51
Mike Lowery
  • 2,630
  • 4
  • 34
  • 44
  • I don't know whether this applies to your situation, but generally you should implement `IDisposable` yourself to clean up resources, and only use a destructor if there is unmanaged stuff to clean up. – C.Evenhuis Jan 26 '17 at 18:28
  • 1
    @C.Evenhuis C# doesn't even have destructors, it has finalizers which do a very different job – Mgetz Jan 26 '17 at 18:31
  • @C.Evenhuis Considering we can see the definition of the finalizer, we can in fact see that there is no unmanaged resource, and so there should be no finalizer, rather it should implement `IDisposalbe`. – Servy Jan 26 '17 at 18:49
  • My example above doesn't show it but the class is actually a singleton in which case implementing IDisposable doesn't make much sense, otherwise I'd agree. Still, there's no guarantee that `Dispose()` will ever be called, hence the need for a destructor. – Mike Lowery Jan 26 '17 at 19:11
  • @servy How do you know that `MyObj` doesn't contain unmanaged resources that should be cleaned up by calling its `Dispose()` method? – Mike Lowery Jan 26 '17 at 19:19
  • 1
    @DiskCrasher I expect that it does (if perhaps though some number of layers of indirection), but *it is responsible for cleaning them up in a finalizer* if it feels that it's merited. `MyObj` is itself a managed object (even if it contains an unmanaged resource), and as such, you should not be accessing it in a finalizer at all. – Servy Jan 26 '17 at 19:21
  • @Servy Which leads to the question of what's considered managed vs. unmanaged code. I've seen a lot of posts about this but nothing that was crystal clear (to me at least). For example, the .Net Socket class likely performs some unmanaged calls and also implements IDisposable. Does that make it "unmanaged code" that needs to be disposed of by the caller? – Mike Lowery Jan 26 '17 at 20:17
  • 1
    @DiskCrasher If it's a class, it's a managed object. An unmanged object is like a file handle, a network socket, etc. The `Socket` class is a *managed* object that is responsible for managing an *unmanaged* resource (the actual OS socket). Disposing of a class is always, 100% of the time, a managed operation, and you shouldn't be doing that in a finalizer. An unmanaged resource would be, say, calling out to an OS hook to tell it that you no longer need a socket and that it should be closed (which is what the `Socket` class will do in *its* finalizer). – Servy Jan 26 '17 at 20:19
  • @DiskCrasher Put more simply, 100% of the code that you write is cleaning up a managed resource. I'm reasonably confident in saying that you're never going to have an unmanaged resource you need to clean up ever. Only a *very* small number of C# programmers *ever* will. You'll virtually certain to only ever be using managed wrappers for unmanaged resources. – Servy Jan 26 '17 at 20:21
  • @Servy This was basically my understanding in the beginning, that all .Net Framework objects are considered managed. Only when you do something like call an external unmanaged DLL do you need to worry about cleanup. But when researching this topic several things I read seemed to imply otherwise. – Mike Lowery Jan 26 '17 at 20:27
  • @DiskCrasher You of course need to implement `IDisoposable` and ensure that you call `Dispose`, you just shouldn't have a finalizer. – Servy Jan 26 '17 at 20:30
  • @Mgetz MSDN still calls it a destructor (https://msdn.microsoft.com/en-us/library/66x5fx1b.aspx). I'm not suitable to argue about that, though. – C.Evenhuis Jan 26 '17 at 22:34
  • @C.Evenhuis I don't care what MSDN mislabels them. ECMA 334 the C# standard calls them finalizers: [8.7.9 Finalizers](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf). They were deliberately not called destructors because destructors run at end of scope. Finalizers run on finalization. – Mgetz Jan 26 '17 at 22:48
  • @Mgetz I can't help responding to your comment - I think the reasoning for calling it destructor is because its syntax resembles that of a constructor, and the reason for _not_ calling it a destructor would probably be to avoid confusion with other languages - neither references say the other is wrong. If C# doesn't have destructors, how would you know they would run at end of scope? _Static constructors_ can be called before accessing a class. – C.Evenhuis Jan 27 '17 at 13:03
  • @C.Evenhuis funny you you should [mention that](https://github.com/dotnet/roslyn/issues/161) there is just such a proposal to allow RAII in C# because the `IDisposable` pattern has been so problematic. – Mgetz Jan 27 '17 at 13:06

2 Answers2

3

This should be not a problem. Static fields are not related this way to the instance of the defining type in terms of memory representation.

Check this post for more detailed info: How exactly do static fields work internally?

Community
  • 1
  • 1
vasil oreshenski
  • 2,788
  • 1
  • 14
  • 21
2

Presence of static fields has no impact on timing when object will be garbage collected (and hence finalized). The instance will be finalized just fine at moment comparable to time it happens without static field.

The only impact static fields have on instances is that static initialization happens before first instance is created thus potentially making creation of first instance slower than the rest.

Note: code in the post shows invalid implementation of finalizer because it refers to other manged object and tries to call method on it. It results in undefined behavior for both cases (with/without static field).

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • 1
    The question is whether or not a class will be disposed when it contains static content, not so much about timing (which implies it can be). – Mike Lowery Jan 26 '17 at 19:15
  • @DiskCrasher I think I've misread your question completely - I read it "whether ` ~Switch()` finalizer will be called at different time (or at all) if there is static field" and answered that by stating that static fields will not change timing of that call to finalizer (hence if call happens without static field it will happen at comparable time when there is static field in the class). But your real question seem to be about actual disposing - than based on code in the post disposing of `m_object` will be undefined in both cases (as state if other objects is undefined in finalizer) – Alexei Levenkov Jan 26 '17 at 19:34