Coding Shorts: IDisposable and IAsyncDisposable in C#

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi this is shawn wildemuth with coding shorts today we're going to talk about the eye disposable pattern c sharp is a managed language when we say manage we mostly just mean memory managed there's a lot of different resources that you may find that can't be managed just by memory we can think about expensive resources like file handles database connections windows handles other things like that there you're going to need to clean up on your own and that's where the eye disposable pattern comes in so i'm going to talk to you about deterministic destruction today let's take a look [Music] so let's take a look at this pretty simple program i'm writing i have just a console app that when it runs i'm going to instantiate this valuable class that we'll look at in a minute and it is just going to process some string return some string that i can write out not going to do all that interesting of a thing we look at the process here it's just using a memory stream to do some encoding and decoding of information again it's not important what it's doing but it's important that inside of this class i don't know about anything that might be a valuable resource a file handle a connection string to a database a i o port a window handle who knows what it's all from my perspective of using it here i don't know anything about it right and so in fact when we run this that's what we want we put in hello world we get back hello world and everything seems fine especially in this being a console lap because if we're leaking memory the process is going to get torn down and we're never going to know that but in fact we have a leak here and a lot of you probably already noticed it that we're using a stream here and if we look at stream i'm using f12 to go ahead and look at the definition of this memory stream class we'll see that this doesn't look very interesting let's go down into its implementation and we actually see i disposable that's this magic interface we actually also see i async disposable which we'll talk about a little later but i disposable is this interface that is essentially tagged onto stream to say hey you know what this has resources that we need to have control over when they get destroyed this is an indication when you're looking at something that it requires something special and so here we can just use something called the using statement to do what's called deterministic deconstruction by putting all of our code inside of a using statement we're telling it that this object requires an eye disposable and if we change this to something like a new string it should complain here because what does it say string is not convertible to eye disposable therefore it can't be used this using statement is specifically for things that support i disposable and what is it going to do it's effectively putting and using is the same let me go back that's coming in here and saying stream dot dispose saying please clean up my mess here the reason this is important is we want to determine when to get rid of resources that are finite again back to window handles database connections etc and so let's get rid of our dispose and go back to using the using statement right and so we're going to say var stream and this is a scope so you may need to do some things about if this needs to be exposed outside but this pattern of having it around including the return simply says okay when the scope is gone please call the eye disposable for me that's all this was really doing and this is fine when you're just using local objects for a short amount of time streams are a common case here but what if we wanted to say this is going to be in a constructor instead no parameters and instead we want this to be a field for stream right that stream there and this will continue to work except that like before we have a leak because this memory stream is going to live as long as the object lives and we don't know when it's going to be cleaned up in fact no one is actually calling disposable for us so one of the things you will see and especially if you come from other languages you might want to use a finalizer which is sort of c sharps version of a destructor and so a finalizer takes the form of the tilde and then the name of the class and this says hey call some code when the garbage collector is going to get rid of this object and so i can go okay i'll just go ahead in case it's not cleaned up here i'll just go ahead and say let's close it and stream dot dispose right that's a clean thing to do we can say is valuable in fact over here let's just use console.writeline and say closing and disposing so we can see when this actually happens right we're just using this finalizer to go let's just make sure that if things aren't cleaned up we're gonna handle it in the destructor so let's run that notice it never happens and in a console lap it never happens because there's never memory pressure and so the finalizer never gets called it never gets called because when the process starts to tear itself down it goes oh you know what this is worth it let's just destroy that whole section of memory we're not even going to call any of this code because we want to exit quickly in something longer lived like a web server you might notice that this valuable eventually gets called but it's eventually we don't have any control over when this actually happens and that's an important idea here and so if we want to control when it happens and let's say this stream is being used by more parts of our application but once the valuable object is done we want to get rid of it what do we do we of course we implement the interface i disposable let's go ahead and just implement that interface simply so we can kind of talk about how that's done all it does is define an interface called i dispose but remember the more important part is this interface that tells the user of this class that there is something in here that is more than just memory now remember we're talking about unmanaged resources so these are resources that aren't managed by c-sharp itself again things like file handles window handles database connections are the common ones but you can find other resources that might be important to handle knowing when they are destroyed because what we're talking about is deterministic destruction we want to know when and control when this destruction happens so in the case of this now that we have disposed what can we do well let's go ahead and just move all our code here into the dispose and unsurprisingly we can then say using because now the valuable includes i disposable let's move this in the scope or we could even do this we could say var result equals empty string and then assign the empty string and then write it out again this is a scope like any other so you're going to need to handle what's in and out of that scope let's go ahead and run this again and we can see here closing and disposing was in fact called because after this using statement but before this last right line happened what happened it called the dispose for us well that's great we can finally sort of take control over that lifetime and that is good but what if the user of the class didn't use the using statement what do you do then let's go back to value and one of the common patterns here is actually say stream equals null and then in the finalizer you can still check if stream does not equal no or we're in c sharp 9 now so is not null and what can we do we can call dispose and so this is sort of belts and suspenders if they're calling disposed great if not then eventually the disposal be called when the object is collected so you don't end up having strike database or file handles sitting out there unused and this is good but it's not great we still have a couple of issues here one is that we're going to want a member here i'll call is disposing and this is mostly to handle the race condition of disposing is in the middle of being called and then the finalizer actually gets called and you don't want to get sort of in the middle of that so you're just going to say if is disposing sorry if not disposing then is disposing true and then we can go ahead and go on with the disposing and so dispose can be called here because it can't end up being called at the same time and at the same time this won't call it because stream is ends sort of protects you in both situations and so in that way you can have both the belt and suspenders to make sure this is disposed and again handling this well is a pattern that in fact you can see in visual studio and visual studio code there's actually a pattern for doing most of this for you the last piece i'll talk about is actually also supporting which is a common pattern i async disposable and this interface is very similar the difference here is it's returning a value task and so what this is going to allow you to do is if you have operations that are asynchronous you allow that disposed to happen without tying up the thread for us we can actually do the same thing here because we don't want them both called but in the case of stream we might have a stream dot flush async you know let's say that was part of the closing function was to asynchronously close it let's come back up here and say stream dot flush right well in this case we don't want to take up that thread extra so we could actually say await flush and make this async of course now i could also hear say await stream dispose async because of course it supports it as well and when you call dispose async you're also going to want to configure the await to say false because we want this in case of failure not to throw an exception but to just go away we're going to assume that it's going to try to do its best to be disposable now what happens here in this using statement is this is only going to call the eye disposable it's never going to call the iasync disposable but when i think disposable is there you can opt into it by saying await using now this works normally inside of an asynchronous method by saying this is an asynchronous disposal and will opt into the eye async dispose method as well that's an important discerning and so it is your responsibility as you write classes that consume resources that are disposable that you dispose them as well now one of the ideas here is what if i'm using something that's very special that doesn't support eye disposable but i'm really doing something really low level in that case you're going to want to clean up your own unmanaged resources so imagine if you're doing interrupt with 132 and you needed to do it like a memory page file it's going to be up to you to actually call those underlying things that dispose of it but it's important that even though c-sharp is handling the garbage collection managing the memory for us that's not going to manage the sort of resources that we may not think of as just memory and it could be any of the kinds of things i've been talking about thanks for joining me on this coding shorts my name is sean wilden youth as usual thanks for coming [Music]
Info
Channel: swildermuth
Views: 937
Rating: undefined out of 5
Keywords: C#, .NET, IDisposable, IAsyncDisposable, Programming, Software Development, Deterministic Destruction
Id: mG4PFlajbzs
Channel Id: undefined
Length: 12min 21sec (741 seconds)
Published: Sun Apr 11 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.