The essence of my task is to come up with a situation when a finalizer is needed. I wanted to make an example with the file system. A reference to an instance of the FileStream class is passed to the class and, in theory, when removing my class, the stream should close. Here is my example: there is a class that in the constructor takes an instance of the FileStream class as an argument:

 class MyClass { FileStream _fileStream; public MyClass(ref FileStream filestream) { this._fileStream = filestream; } ~MyClass() { Console.WriteLine("Object destroy."); _fileStream.Close(); _fileStream.Dispose(); _fileStream = null; GC.Collect(); } } 

The main program:

 static void Main(string[] args) { var path = Directory.GetCurrentDirectory() + @"\..\..\folder\"; FileStream fileStream = new FileStream(path + "Text.txt", FileMode.OpenOrCreate); MyClass file = new ChildClass(fileStream); file = null; GC.Collect(); // fileStream.Close(); С этой строкой работает без исключения FileStream fileStream2 = new FileStream(path + "Text.txt", FileMode.OpenOrCreate); Console.ReadKey(); } 

When you create an instance of fileStream2 , an exception occurs stating that the file is occupied by another process. Why is the transfer of the link not working? Why is it that _fileStream and filestream are two different instances pointing to different links? The ref keyword is here as an experiment. After all, instances of reference types are passed by reference.

  • and the line is displayed? Console.WriteLine("Object destroy."); ? - Grundy
  • Yes, "Object destroy" is displayed. - raskopin
  • How do you know that it is output before the assignment of fileStream2? - Grundy

2 answers 2

The presence of ref next to the type of the parameter indicates that in the function this parameter can be reassigned and this reassignment will affect the called code. In your case, such a reassignment does not occur, because no assignment of the form:

 filestream = нечто; 

in the body of the function that takes the ref parameter. Those. You simply did not use what ref provides. Therefore, even after the call:

 _fileStream = null; 

in the finalizer, there remains a fileStream link associated with the open file. This leads to the aforementioned exception.

If you change the constructor to the following:

 public MyClass(ref FileStream filestream) { this._fileStream = filestream; filestream = null; // изменяем ref-параметр } 

then the error should go away.

     _fileStream.Close(); _fileStream.Dispose(); 

    It is not right. First, the managed objects will collect the garbage collector itself, so it is not known whether the object is still alive. This should be done by the Dispose method, not the finalizer. Secondly, Close and Dispose are the same. It makes no sense to call them both.

     GC.Collect(); 

    And it is generally hard. He himself knows when to run. Besides, he does his job and so it is - we are in the finalizer.

    PS: I advise you to read the article http://sergeyteplyakov.blogspot.ru/2011/09/dispose-pattern.html

    • You probably do not quite understand me. I understand that it is not necessary to interfere with the work of the garbage collector. But there is such a task - to show the case when necessary finalizer. Therefore, in the example, I reset the link myself and call GC to know exactly when this object will be deleted. And the fact that there are going in a row Close (); Dispose (); and GC.Collect () is to show that none of these methods cleared the stream. - raskopin
    • @raskopin, no, re-read the answer. - Qwertiy