When is StreamWriter disposed?
I have a small class I threw together to implement a quick logger. I composed it with a private System.IO.StreamWriter
which is instantiated in the constructor. Because the way I'm using is prevents me from implementing a using
block, I added a finalizer and called the StreamWriter's Dispose()
method in it. However, when executing, that finalizer throws an exception because the StreamWriter has already been disposed.
System.ObjectDisposedException - Cannot access a closed file.
I'm confused how this happened and I'm wondering if this means I don't need to worry about cleaning up the StreamWriter. Here is my class:
public class TextFileLogger : AbstractTextLogger
{
private const string LogPath = @"C:";
private const string LogFileName = "MyFile.log.txt";
private readonly StreamWriter _writer;
public TextFileLogger()
{
_writer = new StreamWriter($"{LogPath}{LogFileName}", true);
_writer.AutoFlush = true;
}
~TextFileLogger()
{
_writer.Dispose();
}
protected override void WriteLine(string line)
{
_writer.WriteLine(line);
}
}
c# .net idisposable finalizer
add a comment |
I have a small class I threw together to implement a quick logger. I composed it with a private System.IO.StreamWriter
which is instantiated in the constructor. Because the way I'm using is prevents me from implementing a using
block, I added a finalizer and called the StreamWriter's Dispose()
method in it. However, when executing, that finalizer throws an exception because the StreamWriter has already been disposed.
System.ObjectDisposedException - Cannot access a closed file.
I'm confused how this happened and I'm wondering if this means I don't need to worry about cleaning up the StreamWriter. Here is my class:
public class TextFileLogger : AbstractTextLogger
{
private const string LogPath = @"C:";
private const string LogFileName = "MyFile.log.txt";
private readonly StreamWriter _writer;
public TextFileLogger()
{
_writer = new StreamWriter($"{LogPath}{LogFileName}", true);
_writer.AutoFlush = true;
}
~TextFileLogger()
{
_writer.Dispose();
}
protected override void WriteLine(string line)
{
_writer.WriteLine(line);
}
}
c# .net idisposable finalizer
5
You can't do that. Finalizers (aka destructors) run on a separate thread with no guarantees that other managed objects to which your object refer still exist. The only things you should clean up in a Finalizer are unmanaged resources. Make your TextFileLogger Disposable (implement IDisposable) and read up on the "Dispose Pattern" to get it just right. If a class has no native resources (like yours) it should not have a Finalizer
– Flydog57
Nov 21 '18 at 20:00
docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…
– tkausl
Nov 21 '18 at 20:00
@Flydog57 - I'm familiar with implementing IDisposable, and have done so a few times before. I thought I could somehow just dispose of the StreamWriter inside my class without needing a using block. Since this is a quick and dirty, temporary thing, I will probably just need to new up the StreamWriter in every call to WriteLine so I can use it in a using block. This is awful, and will take about 14.5 times longer in execution time, according to my measurements, but for a short lived project, I'd rather take that performance hit than completely rearchitect everything.
– bubbleking
Nov 21 '18 at 21:13
Add a Dispose method for the things somewhere else in your code. As long as it's in your normal code, you can dispose of it. However, once you get in Finalizer code, all the "managed code guarantees" mostly get wiped off the table. Finalizers are very easy to mess up.
– Flydog57
Nov 21 '18 at 21:17
add a comment |
I have a small class I threw together to implement a quick logger. I composed it with a private System.IO.StreamWriter
which is instantiated in the constructor. Because the way I'm using is prevents me from implementing a using
block, I added a finalizer and called the StreamWriter's Dispose()
method in it. However, when executing, that finalizer throws an exception because the StreamWriter has already been disposed.
System.ObjectDisposedException - Cannot access a closed file.
I'm confused how this happened and I'm wondering if this means I don't need to worry about cleaning up the StreamWriter. Here is my class:
public class TextFileLogger : AbstractTextLogger
{
private const string LogPath = @"C:";
private const string LogFileName = "MyFile.log.txt";
private readonly StreamWriter _writer;
public TextFileLogger()
{
_writer = new StreamWriter($"{LogPath}{LogFileName}", true);
_writer.AutoFlush = true;
}
~TextFileLogger()
{
_writer.Dispose();
}
protected override void WriteLine(string line)
{
_writer.WriteLine(line);
}
}
c# .net idisposable finalizer
I have a small class I threw together to implement a quick logger. I composed it with a private System.IO.StreamWriter
which is instantiated in the constructor. Because the way I'm using is prevents me from implementing a using
block, I added a finalizer and called the StreamWriter's Dispose()
method in it. However, when executing, that finalizer throws an exception because the StreamWriter has already been disposed.
System.ObjectDisposedException - Cannot access a closed file.
I'm confused how this happened and I'm wondering if this means I don't need to worry about cleaning up the StreamWriter. Here is my class:
public class TextFileLogger : AbstractTextLogger
{
private const string LogPath = @"C:";
private const string LogFileName = "MyFile.log.txt";
private readonly StreamWriter _writer;
public TextFileLogger()
{
_writer = new StreamWriter($"{LogPath}{LogFileName}", true);
_writer.AutoFlush = true;
}
~TextFileLogger()
{
_writer.Dispose();
}
protected override void WriteLine(string line)
{
_writer.WriteLine(line);
}
}
c# .net idisposable finalizer
c# .net idisposable finalizer
asked Nov 21 '18 at 19:55
bubblekingbubbleking
1,07311327
1,07311327
5
You can't do that. Finalizers (aka destructors) run on a separate thread with no guarantees that other managed objects to which your object refer still exist. The only things you should clean up in a Finalizer are unmanaged resources. Make your TextFileLogger Disposable (implement IDisposable) and read up on the "Dispose Pattern" to get it just right. If a class has no native resources (like yours) it should not have a Finalizer
– Flydog57
Nov 21 '18 at 20:00
docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…
– tkausl
Nov 21 '18 at 20:00
@Flydog57 - I'm familiar with implementing IDisposable, and have done so a few times before. I thought I could somehow just dispose of the StreamWriter inside my class without needing a using block. Since this is a quick and dirty, temporary thing, I will probably just need to new up the StreamWriter in every call to WriteLine so I can use it in a using block. This is awful, and will take about 14.5 times longer in execution time, according to my measurements, but for a short lived project, I'd rather take that performance hit than completely rearchitect everything.
– bubbleking
Nov 21 '18 at 21:13
Add a Dispose method for the things somewhere else in your code. As long as it's in your normal code, you can dispose of it. However, once you get in Finalizer code, all the "managed code guarantees" mostly get wiped off the table. Finalizers are very easy to mess up.
– Flydog57
Nov 21 '18 at 21:17
add a comment |
5
You can't do that. Finalizers (aka destructors) run on a separate thread with no guarantees that other managed objects to which your object refer still exist. The only things you should clean up in a Finalizer are unmanaged resources. Make your TextFileLogger Disposable (implement IDisposable) and read up on the "Dispose Pattern" to get it just right. If a class has no native resources (like yours) it should not have a Finalizer
– Flydog57
Nov 21 '18 at 20:00
docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…
– tkausl
Nov 21 '18 at 20:00
@Flydog57 - I'm familiar with implementing IDisposable, and have done so a few times before. I thought I could somehow just dispose of the StreamWriter inside my class without needing a using block. Since this is a quick and dirty, temporary thing, I will probably just need to new up the StreamWriter in every call to WriteLine so I can use it in a using block. This is awful, and will take about 14.5 times longer in execution time, according to my measurements, but for a short lived project, I'd rather take that performance hit than completely rearchitect everything.
– bubbleking
Nov 21 '18 at 21:13
Add a Dispose method for the things somewhere else in your code. As long as it's in your normal code, you can dispose of it. However, once you get in Finalizer code, all the "managed code guarantees" mostly get wiped off the table. Finalizers are very easy to mess up.
– Flydog57
Nov 21 '18 at 21:17
5
5
You can't do that. Finalizers (aka destructors) run on a separate thread with no guarantees that other managed objects to which your object refer still exist. The only things you should clean up in a Finalizer are unmanaged resources. Make your TextFileLogger Disposable (implement IDisposable) and read up on the "Dispose Pattern" to get it just right. If a class has no native resources (like yours) it should not have a Finalizer
– Flydog57
Nov 21 '18 at 20:00
You can't do that. Finalizers (aka destructors) run on a separate thread with no guarantees that other managed objects to which your object refer still exist. The only things you should clean up in a Finalizer are unmanaged resources. Make your TextFileLogger Disposable (implement IDisposable) and read up on the "Dispose Pattern" to get it just right. If a class has no native resources (like yours) it should not have a Finalizer
– Flydog57
Nov 21 '18 at 20:00
docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…
– tkausl
Nov 21 '18 at 20:00
docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…
– tkausl
Nov 21 '18 at 20:00
@Flydog57 - I'm familiar with implementing IDisposable, and have done so a few times before. I thought I could somehow just dispose of the StreamWriter inside my class without needing a using block. Since this is a quick and dirty, temporary thing, I will probably just need to new up the StreamWriter in every call to WriteLine so I can use it in a using block. This is awful, and will take about 14.5 times longer in execution time, according to my measurements, but for a short lived project, I'd rather take that performance hit than completely rearchitect everything.
– bubbleking
Nov 21 '18 at 21:13
@Flydog57 - I'm familiar with implementing IDisposable, and have done so a few times before. I thought I could somehow just dispose of the StreamWriter inside my class without needing a using block. Since this is a quick and dirty, temporary thing, I will probably just need to new up the StreamWriter in every call to WriteLine so I can use it in a using block. This is awful, and will take about 14.5 times longer in execution time, according to my measurements, but for a short lived project, I'd rather take that performance hit than completely rearchitect everything.
– bubbleking
Nov 21 '18 at 21:13
Add a Dispose method for the things somewhere else in your code. As long as it's in your normal code, you can dispose of it. However, once you get in Finalizer code, all the "managed code guarantees" mostly get wiped off the table. Finalizers are very easy to mess up.
– Flydog57
Nov 21 '18 at 21:17
Add a Dispose method for the things somewhere else in your code. As long as it's in your normal code, you can dispose of it. However, once you get in Finalizer code, all the "managed code guarantees" mostly get wiped off the table. Finalizers are very easy to mess up.
– Flydog57
Nov 21 '18 at 21:17
add a comment |
1 Answer
1
active
oldest
votes
The only things you are allowed to access in a finalizer are objects that are rooted (like static variables) or objects that derive from CriticalFinalizerObject.
The problem is the finalizer is not deterministic, it is allowed to run in any order it feels like. The problem you ran in to is because the text writer was finalized before your class.
You need to either just "hope for the best" and let the writer's finalizer to do the work or you need to refactor your code so your class is disposeable itself and that calls the stream writer's dispose method.
Would "hope for the best" be what my class would be doing if I were to simply remove the finalizer and leave the rest unchanged? I'm a bit surprised by your answer and the comments suggesting I implement IDisposable on my class. I'm familiar with that concept, and have done so before, but I thought there was some way to simply call an IDisposable's Dispose method without needing a using block to trigger it. I was hoping for a "has-a" instead of an "is-a" approach with this class, and implementing IDisposable is probably not an option here (the consuming code can't use a using block either).
– bubbleking
Nov 21 '18 at 21:05
Yes removing the finalizer would be the "hope for the best" option.
– Scott Chamberlain
Nov 22 '18 at 0:59
I decided to go with just implementing IDisposable, but not the pattern that includes the virtual method with the boolean disposing parameter and the call to GC.SuppressFinalizer. This project wasn't worth creating a whole base class hierarchy just for that. Instead, I merely called the StreamWriter's Dispose() method from my class' Dispose() method, and I found a place to use my class in a using block (which was a bit hacky, but it works). It's basically like the accepted answer on this: stackoverflow.com/questions/10038321/…
– bubbleking
Nov 22 '18 at 12:23
Do you have any thoughts on that simple version (in my previous comment's link)? I'm not sure why the only recommendation one can ever find is to implement that entire IDisposable base class with public and virtual protected methods, and make the call to GC.SupressFinalize(). It seems like the simple version should do the job, but I guess there's something wrong with it, since you never see it in docs or recommendations. I guess I'm still just hoping for the best. ;)
– bubbleking
Nov 22 '18 at 12:28
I think the advice to have a virtual method with a bool is a bad pattern, IMHO. Here is a good article that explains a better patern that you will never need to check for that bool again codeproject.com/Articles/29534/…
– Scott Chamberlain
Nov 22 '18 at 19:25
|
show 1 more comment
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53419619%2fwhen-is-streamwriter-disposed%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The only things you are allowed to access in a finalizer are objects that are rooted (like static variables) or objects that derive from CriticalFinalizerObject.
The problem is the finalizer is not deterministic, it is allowed to run in any order it feels like. The problem you ran in to is because the text writer was finalized before your class.
You need to either just "hope for the best" and let the writer's finalizer to do the work or you need to refactor your code so your class is disposeable itself and that calls the stream writer's dispose method.
Would "hope for the best" be what my class would be doing if I were to simply remove the finalizer and leave the rest unchanged? I'm a bit surprised by your answer and the comments suggesting I implement IDisposable on my class. I'm familiar with that concept, and have done so before, but I thought there was some way to simply call an IDisposable's Dispose method without needing a using block to trigger it. I was hoping for a "has-a" instead of an "is-a" approach with this class, and implementing IDisposable is probably not an option here (the consuming code can't use a using block either).
– bubbleking
Nov 21 '18 at 21:05
Yes removing the finalizer would be the "hope for the best" option.
– Scott Chamberlain
Nov 22 '18 at 0:59
I decided to go with just implementing IDisposable, but not the pattern that includes the virtual method with the boolean disposing parameter and the call to GC.SuppressFinalizer. This project wasn't worth creating a whole base class hierarchy just for that. Instead, I merely called the StreamWriter's Dispose() method from my class' Dispose() method, and I found a place to use my class in a using block (which was a bit hacky, but it works). It's basically like the accepted answer on this: stackoverflow.com/questions/10038321/…
– bubbleking
Nov 22 '18 at 12:23
Do you have any thoughts on that simple version (in my previous comment's link)? I'm not sure why the only recommendation one can ever find is to implement that entire IDisposable base class with public and virtual protected methods, and make the call to GC.SupressFinalize(). It seems like the simple version should do the job, but I guess there's something wrong with it, since you never see it in docs or recommendations. I guess I'm still just hoping for the best. ;)
– bubbleking
Nov 22 '18 at 12:28
I think the advice to have a virtual method with a bool is a bad pattern, IMHO. Here is a good article that explains a better patern that you will never need to check for that bool again codeproject.com/Articles/29534/…
– Scott Chamberlain
Nov 22 '18 at 19:25
|
show 1 more comment
The only things you are allowed to access in a finalizer are objects that are rooted (like static variables) or objects that derive from CriticalFinalizerObject.
The problem is the finalizer is not deterministic, it is allowed to run in any order it feels like. The problem you ran in to is because the text writer was finalized before your class.
You need to either just "hope for the best" and let the writer's finalizer to do the work or you need to refactor your code so your class is disposeable itself and that calls the stream writer's dispose method.
Would "hope for the best" be what my class would be doing if I were to simply remove the finalizer and leave the rest unchanged? I'm a bit surprised by your answer and the comments suggesting I implement IDisposable on my class. I'm familiar with that concept, and have done so before, but I thought there was some way to simply call an IDisposable's Dispose method without needing a using block to trigger it. I was hoping for a "has-a" instead of an "is-a" approach with this class, and implementing IDisposable is probably not an option here (the consuming code can't use a using block either).
– bubbleking
Nov 21 '18 at 21:05
Yes removing the finalizer would be the "hope for the best" option.
– Scott Chamberlain
Nov 22 '18 at 0:59
I decided to go with just implementing IDisposable, but not the pattern that includes the virtual method with the boolean disposing parameter and the call to GC.SuppressFinalizer. This project wasn't worth creating a whole base class hierarchy just for that. Instead, I merely called the StreamWriter's Dispose() method from my class' Dispose() method, and I found a place to use my class in a using block (which was a bit hacky, but it works). It's basically like the accepted answer on this: stackoverflow.com/questions/10038321/…
– bubbleking
Nov 22 '18 at 12:23
Do you have any thoughts on that simple version (in my previous comment's link)? I'm not sure why the only recommendation one can ever find is to implement that entire IDisposable base class with public and virtual protected methods, and make the call to GC.SupressFinalize(). It seems like the simple version should do the job, but I guess there's something wrong with it, since you never see it in docs or recommendations. I guess I'm still just hoping for the best. ;)
– bubbleking
Nov 22 '18 at 12:28
I think the advice to have a virtual method with a bool is a bad pattern, IMHO. Here is a good article that explains a better patern that you will never need to check for that bool again codeproject.com/Articles/29534/…
– Scott Chamberlain
Nov 22 '18 at 19:25
|
show 1 more comment
The only things you are allowed to access in a finalizer are objects that are rooted (like static variables) or objects that derive from CriticalFinalizerObject.
The problem is the finalizer is not deterministic, it is allowed to run in any order it feels like. The problem you ran in to is because the text writer was finalized before your class.
You need to either just "hope for the best" and let the writer's finalizer to do the work or you need to refactor your code so your class is disposeable itself and that calls the stream writer's dispose method.
The only things you are allowed to access in a finalizer are objects that are rooted (like static variables) or objects that derive from CriticalFinalizerObject.
The problem is the finalizer is not deterministic, it is allowed to run in any order it feels like. The problem you ran in to is because the text writer was finalized before your class.
You need to either just "hope for the best" and let the writer's finalizer to do the work or you need to refactor your code so your class is disposeable itself and that calls the stream writer's dispose method.
answered Nov 21 '18 at 20:04
Scott ChamberlainScott Chamberlain
99.2k25185328
99.2k25185328
Would "hope for the best" be what my class would be doing if I were to simply remove the finalizer and leave the rest unchanged? I'm a bit surprised by your answer and the comments suggesting I implement IDisposable on my class. I'm familiar with that concept, and have done so before, but I thought there was some way to simply call an IDisposable's Dispose method without needing a using block to trigger it. I was hoping for a "has-a" instead of an "is-a" approach with this class, and implementing IDisposable is probably not an option here (the consuming code can't use a using block either).
– bubbleking
Nov 21 '18 at 21:05
Yes removing the finalizer would be the "hope for the best" option.
– Scott Chamberlain
Nov 22 '18 at 0:59
I decided to go with just implementing IDisposable, but not the pattern that includes the virtual method with the boolean disposing parameter and the call to GC.SuppressFinalizer. This project wasn't worth creating a whole base class hierarchy just for that. Instead, I merely called the StreamWriter's Dispose() method from my class' Dispose() method, and I found a place to use my class in a using block (which was a bit hacky, but it works). It's basically like the accepted answer on this: stackoverflow.com/questions/10038321/…
– bubbleking
Nov 22 '18 at 12:23
Do you have any thoughts on that simple version (in my previous comment's link)? I'm not sure why the only recommendation one can ever find is to implement that entire IDisposable base class with public and virtual protected methods, and make the call to GC.SupressFinalize(). It seems like the simple version should do the job, but I guess there's something wrong with it, since you never see it in docs or recommendations. I guess I'm still just hoping for the best. ;)
– bubbleking
Nov 22 '18 at 12:28
I think the advice to have a virtual method with a bool is a bad pattern, IMHO. Here is a good article that explains a better patern that you will never need to check for that bool again codeproject.com/Articles/29534/…
– Scott Chamberlain
Nov 22 '18 at 19:25
|
show 1 more comment
Would "hope for the best" be what my class would be doing if I were to simply remove the finalizer and leave the rest unchanged? I'm a bit surprised by your answer and the comments suggesting I implement IDisposable on my class. I'm familiar with that concept, and have done so before, but I thought there was some way to simply call an IDisposable's Dispose method without needing a using block to trigger it. I was hoping for a "has-a" instead of an "is-a" approach with this class, and implementing IDisposable is probably not an option here (the consuming code can't use a using block either).
– bubbleking
Nov 21 '18 at 21:05
Yes removing the finalizer would be the "hope for the best" option.
– Scott Chamberlain
Nov 22 '18 at 0:59
I decided to go with just implementing IDisposable, but not the pattern that includes the virtual method with the boolean disposing parameter and the call to GC.SuppressFinalizer. This project wasn't worth creating a whole base class hierarchy just for that. Instead, I merely called the StreamWriter's Dispose() method from my class' Dispose() method, and I found a place to use my class in a using block (which was a bit hacky, but it works). It's basically like the accepted answer on this: stackoverflow.com/questions/10038321/…
– bubbleking
Nov 22 '18 at 12:23
Do you have any thoughts on that simple version (in my previous comment's link)? I'm not sure why the only recommendation one can ever find is to implement that entire IDisposable base class with public and virtual protected methods, and make the call to GC.SupressFinalize(). It seems like the simple version should do the job, but I guess there's something wrong with it, since you never see it in docs or recommendations. I guess I'm still just hoping for the best. ;)
– bubbleking
Nov 22 '18 at 12:28
I think the advice to have a virtual method with a bool is a bad pattern, IMHO. Here is a good article that explains a better patern that you will never need to check for that bool again codeproject.com/Articles/29534/…
– Scott Chamberlain
Nov 22 '18 at 19:25
Would "hope for the best" be what my class would be doing if I were to simply remove the finalizer and leave the rest unchanged? I'm a bit surprised by your answer and the comments suggesting I implement IDisposable on my class. I'm familiar with that concept, and have done so before, but I thought there was some way to simply call an IDisposable's Dispose method without needing a using block to trigger it. I was hoping for a "has-a" instead of an "is-a" approach with this class, and implementing IDisposable is probably not an option here (the consuming code can't use a using block either).
– bubbleking
Nov 21 '18 at 21:05
Would "hope for the best" be what my class would be doing if I were to simply remove the finalizer and leave the rest unchanged? I'm a bit surprised by your answer and the comments suggesting I implement IDisposable on my class. I'm familiar with that concept, and have done so before, but I thought there was some way to simply call an IDisposable's Dispose method without needing a using block to trigger it. I was hoping for a "has-a" instead of an "is-a" approach with this class, and implementing IDisposable is probably not an option here (the consuming code can't use a using block either).
– bubbleking
Nov 21 '18 at 21:05
Yes removing the finalizer would be the "hope for the best" option.
– Scott Chamberlain
Nov 22 '18 at 0:59
Yes removing the finalizer would be the "hope for the best" option.
– Scott Chamberlain
Nov 22 '18 at 0:59
I decided to go with just implementing IDisposable, but not the pattern that includes the virtual method with the boolean disposing parameter and the call to GC.SuppressFinalizer. This project wasn't worth creating a whole base class hierarchy just for that. Instead, I merely called the StreamWriter's Dispose() method from my class' Dispose() method, and I found a place to use my class in a using block (which was a bit hacky, but it works). It's basically like the accepted answer on this: stackoverflow.com/questions/10038321/…
– bubbleking
Nov 22 '18 at 12:23
I decided to go with just implementing IDisposable, but not the pattern that includes the virtual method with the boolean disposing parameter and the call to GC.SuppressFinalizer. This project wasn't worth creating a whole base class hierarchy just for that. Instead, I merely called the StreamWriter's Dispose() method from my class' Dispose() method, and I found a place to use my class in a using block (which was a bit hacky, but it works). It's basically like the accepted answer on this: stackoverflow.com/questions/10038321/…
– bubbleking
Nov 22 '18 at 12:23
Do you have any thoughts on that simple version (in my previous comment's link)? I'm not sure why the only recommendation one can ever find is to implement that entire IDisposable base class with public and virtual protected methods, and make the call to GC.SupressFinalize(). It seems like the simple version should do the job, but I guess there's something wrong with it, since you never see it in docs or recommendations. I guess I'm still just hoping for the best. ;)
– bubbleking
Nov 22 '18 at 12:28
Do you have any thoughts on that simple version (in my previous comment's link)? I'm not sure why the only recommendation one can ever find is to implement that entire IDisposable base class with public and virtual protected methods, and make the call to GC.SupressFinalize(). It seems like the simple version should do the job, but I guess there's something wrong with it, since you never see it in docs or recommendations. I guess I'm still just hoping for the best. ;)
– bubbleking
Nov 22 '18 at 12:28
I think the advice to have a virtual method with a bool is a bad pattern, IMHO. Here is a good article that explains a better patern that you will never need to check for that bool again codeproject.com/Articles/29534/…
– Scott Chamberlain
Nov 22 '18 at 19:25
I think the advice to have a virtual method with a bool is a bad pattern, IMHO. Here is a good article that explains a better patern that you will never need to check for that bool again codeproject.com/Articles/29534/…
– Scott Chamberlain
Nov 22 '18 at 19:25
|
show 1 more comment
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53419619%2fwhen-is-streamwriter-disposed%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
5
You can't do that. Finalizers (aka destructors) run on a separate thread with no guarantees that other managed objects to which your object refer still exist. The only things you should clean up in a Finalizer are unmanaged resources. Make your TextFileLogger Disposable (implement IDisposable) and read up on the "Dispose Pattern" to get it just right. If a class has no native resources (like yours) it should not have a Finalizer
– Flydog57
Nov 21 '18 at 20:00
docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…
– tkausl
Nov 21 '18 at 20:00
@Flydog57 - I'm familiar with implementing IDisposable, and have done so a few times before. I thought I could somehow just dispose of the StreamWriter inside my class without needing a using block. Since this is a quick and dirty, temporary thing, I will probably just need to new up the StreamWriter in every call to WriteLine so I can use it in a using block. This is awful, and will take about 14.5 times longer in execution time, according to my measurements, but for a short lived project, I'd rather take that performance hit than completely rearchitect everything.
– bubbleking
Nov 21 '18 at 21:13
Add a Dispose method for the things somewhere else in your code. As long as it's in your normal code, you can dispose of it. However, once you get in Finalizer code, all the "managed code guarantees" mostly get wiped off the table. Finalizers are very easy to mess up.
– Flydog57
Nov 21 '18 at 21:17