简体   繁体   中英

C# destructors and GC not really solving problems compared to C++ destructors

EDIT : This question is meant for comparison between C# and C++ implementations. There is no need to flip dramatic when having a discussion. I personally prefer to develop in C# anyway.

Assume I have the following class:

class Foo {
            FileStream f;
            public Foo() {
                f = File.Open("somefile.txt", FileMode.Open);
            }
            ~Foo() {
                f.Close();
            }
        }

Then I am calling the following in Main:

static void Main(){
    doSomething();
    // this one creates an exception, file in use
    doSomething();
}
static void doSomething(){
    Foo f = new Foo();
}

In C++, this code will work just fine:

    class Foo {
public:
    std::ofstream ofs;
    Foo() { ofs = ofstream("somefile.txt"); }
    ~Foo() { ofs.close(); }
};

void doSomething() {
    Foo f();
}

int main() {
    doSomething();
    doSomething();
    return 0;
}

As when the first doSomething() goes out of scope, the first object calls its destructor and closes the file.

In C# this will always throw an exception saying the file is being used by another process. Obviously the destructor has not been called.

Referring to MSDN page about destructors here , it confuses whoever reads it and makes them think this is actually a destructor. While it is in fact a finializer called by GC whenever GC decides to call it, which is out of my hand.

Yes, I can implement IDisposeable but I do not want every programmer that uses my library to remember calling Dispose() or he will have unhandled exceptions.

I can call GC.Collect() between the two doSomething() methods and no exception will be thrown. Yet again, this will be similar to Dispose() and the user of the library will have to remember it. Not mentioning the zillion warnings from MS telling people PLEASE DO NOT USE GC.Collect() !!

So my question is, if MS wanted to have destructors like C++ does, do they have to only call the Garbage Collector every time a method goes out of scope? Or would it be more complicated for them? What type of complications for such design would there be?

Also, if it was simple, why don't they do it?

Moreover, is there a way to force the destructor in C# to be called upon going out of scope?

EDIT:

I was looking at the C++/CLI implementation, and interestingly the keyword gcnew allows exactly what I want to happen for the C#. So the answer really lies within that implementation. As in their documentation, when the managed object goes out of scope, the GC is called and so the destructor of the managed object is called. And that does not force the user to Dispose the object manually.

That answers the question about how "hard" would it be for MS to make GC work similarly when an object goes out of scope. It just automatically calls GC.Collect() which forces the GC to call the destructor similar to what happens in C++.

As you have surmised, C# does not have deterministic destructors and comparing this to C++ is always going to be "apples to oranges". Further, implementing a destructor on a C# class will cause the GC cleanup of an instance of that class even less deterministic since the GC will put any instance with a destructor into a list to be handled by a separate thread at some later time.

If you want deterministic disposal of an instance, implement the IDisposable interface/pattern. That's what it is there for.

This is not a C# issue. Your class should handle the opening and closing properly.

public static class Foo
{
    public static void DoSomething()
    {
        string someText = "someText";
        using (StreamWriter writer = new StreamWriter("myfile.txt"))
        {
            writer.Write(someText);
            writer.Close();
            writer.Dispose();
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM