What are record types in C# and how they ACTUALLY work

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody i'm nick and this we're going to take a deep dive into the record type that was added in c sharp 9 and was enhanced even further in c sharp 10. we're going to take a look at how it works and all the features around it but also we're going to take a look at how exactly they managed to add the feature in the language without touching the clr and this is a very common mechanism that the c-sharp team is actually using to add features without having to be very invasive when they do so so even if you know how record works check that part of the video because i do think you're going to find it interesting if you like those content and you want to see more make sure you subscribe and hitting the notification bell to get already when i upload a new video now before i move on i want to let you know that i just launched my from zero to hero dependency injection in dotnet course in that course i take you from the very basics of dependency injection to the fundamentals we do a deep dive into the di framework itself we see how we can use some pretty advanced patterns and approaches with the built-in di framework then see how we can extend it even further to add other behaviors and then to top it all off we build the dependency injection framework from scratch this is by far the most complete dependency injection course you will find out there trust me i checked all of them and will teach you everything you need from the very basics to some pretty pretty advanced stuff and it all comes from real world experience building huge scale microservices now the first 100 of you who want to buy this course can use this code right here to get 15 off so check it in the description but if you want and thank you very much for supporting the channel so let's start from the beginning i have a project here in dot net 6 running c sharp 10 and what i want to do first is i want to go on and create a new record so record is a new type we can create here and many people actually seem to think that record is allocated in the memory in some different way or it's like a a structure behind the scenes or something a record just by itself is just a class with special properties that's it it's still a reference type allocated on the heap nothing changes there so i'm gonna go ahead and create a person record here and as you can see this is a perfectly valid record i don't have to have like angle brackets or like this syntax this is still valid syntax but i don't need to i have this shorthand um way of writing a record and i can actually have properties here so i can say full name here and i can also say like date only date of birth so this is a perfectly valid record i can also write this record like this i can go on and actually delete all that and write in this syntax and have them properties written in this way so this is string full name and this is date only date of birth these can be immutable but ideally if we want this to be a one for one to this you want them to be init only because they should only be initialized when you create the record and then these can be default here so these two approaches well same idea now you can totally see why we want to go with the first one is more concise we don't need to expand to this full version we're going to see when we need to now actually before i move on in c shop 10 and i've talked about this in the c shop 10 video we now also have support for a record structs so i can have records track and let's say person has struck and now this is also perfectly valid i can have a record which is extract the value type and also because a record was added first to represent the class you can also be explicit and say record class but as you can see writer detects it and says this is redundant you can remove it so if you just see record assume that it is a class and if you want it to be a struct you have to explicitly specify it but we don't need to touch on that any further now what's the benefits of having a record type well there's actually quite a few let's go here and initialize a person let's say nick here right so i'm going to say new person and i say nick jobs and then new date only 99 and then here we go so we have nick well if this was a class and actually for reference and no pun intended i'm going to make a proper class version of this same record so this is a class i'm going to call it person as class so let's have a class as well i'm gonna go and say nick as class here say new person as class and have the same full name and um date of birth now if i go ahead and i print this and say console.writeline and i print this object and i'm going to run this code now as you can see all i get is that name of the type and this is how classes behave right this is proper behavior it's going to use the tostring method behind the scenes and that's what the default string method does however if i use a record look what happens now i'm going to get a description of everything in that type whether that is the full name and that's the date of birth so i get the actual properties of the thing printed now here's something interesting if i copy a class here twice and i say nick has class two and this is one and i say nick as class equals nick as class two right what do you think will happen when i run this code well i'd expect you to say it's going to print false because this is an equality check and we'll check the reference and since these are two completely different objects allocated in different locations in memory pointing to different things there's no reason why this equality check would say true even though the properties are the same however in record world if i say nick equals nick2 and the properties match then it will say true because equality check checks for the properties not for the reference so that's another thing about records now even though records can have mutable elements in their multiple properties the properties you initialize here are immutable so let me just move this underneath here and we can continue talking about this so they're immutable however you can not really change them but you can create other records and mutate in that new record through a pure function some of those properties the ones you want so let's say nick but older right and then you can have nick equals nick with so i'm using the with operator and let's say a date of birth and that is just one year ago let's say so 1992 so what this will do now and let me just print it and also print the previous one to prove that nothing changed in the previous one so we're going to run this and print nick and then nick but older you can see that the first person was not mutated in any way shape or form but the new one seems to have been cloned into a new object and that's a completely new reference um with a new property here the one i specified here now what's interesting about this waving like copying process is that you can actually override this if you wanted to you can go here in the record and you can create a protect person constructor which actually by default has been already generated for behind the scenes and you can have the old version of the person here and then you can do whatever you want with those properties so the default behavior is all person equals uh full name and then date of birth uh where are we database equals old person dot date of bet so that's how it will behave out of the box and if i run this you will see that it's the same thing but you can totally change that if you like to do so now if you actually want to check the references to see if the references match because like we said if you do one of these if you say let me delete that if you say nick equals to nick 2 because they have the same exact properties you're going to get true but if you actually want to check the references you can totally use the reference equals method that exists in every type so you can say reference equals to this and then that will actually check the references detect that is different and return the truth so a nice thing in case you need it handy another cool feature is that you can actually deconstruct these positional parameters here so if i want to get a var name coma var date of birth i can do that by simply pointing to the record and this will deconstruct and i can actually do this in the shorthand way i forgot so if i do that i can get the properties without having to do nick dot and nick dot to get them and this will actually print themselves let's quickly run this and see that yep it returns the name and the date of birth and this comes out of the box again we haven't actually touched anything in the record this is just bulk standard behavior records also do support inheritance so if you want a record to inherit from another one you can totally do that it's not prevented by the way in case you want to have a different printing mechanism like visualization because when i'm printing a record i'm getting this format here you can totally override that so you can go here and say override the print parameters method and then you get the string builder and you can use the parameters to print this however you want and returned true in the end so i can say builder dot append my full name is and then point to that so let's say full name and then also append uh date of birth is and then date of birth and you can see that this is what the default was printing but the moment we run this now you can see that it's different i mean i screwed up the formatting significantly this should be here and this should be here just run this again because that looks weird yeah that's better but you can totally override this if you want to do so now with all that said how was this feature implemented did you ever think about that how how is this possible well if you remember a while ago i talked to you about a feature called lowering and that's part of the compilation process it happens before your code is turned into iel code it effectively transforms high-level features like record into lower level features and it will also do it with other things like loops and a bunch of other things switches i i can't even name them all you can watch that video if you want to get a full recap on the feature but let's see how learning works on a record which will actually tell us what a record really is so you can go on this website called sharplab.io which is great to see lower code this is the website and i have selected to convert c sharp code into c sharp code but that's the lowered c sharp code and that's gonna be in release mode and i'm gonna paste just a record here i can delete this bit so let's see what the compiler generates and actually because this is a very small window and i can't reformat the size i'm going to copy that and paste it into vs code and see what that looks like there here we go so this is all the code that the compiler will generate and actually see that's the original line we started from and this is what it generated which is quite a bit but you don't want to see what it does when you write a single weight so let's focus on that for now and let's see what it does it's going to first generate a compiler generated embedded attribute and then a nullable attribute for the nullability checks then a nullable context attribute that's quite a bit there then here's our record it is really a class that implements the i equitable interface and then it has the backing fields for the two properties so properties are really a backing field which is well failed and then getters and setters whichever ones you choose to have and then it has a equality contract which you can actually override if you want to this is virtual so i can go back into the compiler and if you want to change that you can say override equality contract and have your own here and this just returns that it is the type of person then you can see the full name being split into the getter that returns the field and the init only method that will initialize the field same for the date time and then you see the public constructor that is added because we generate the class like this so effectively this is this and then you have the two string method which is using that string builder we saw before remember where we could override this print members method well this is the print members method that's the default behavior that's what the part where we override and that's why when we changed it the person and the first angle bracket stayed the same but the rest were overridden and this is how it will print then you can see the quality operator overrides so the not equals and the equals are overreading to point to the also overridden equals operator which is here and if you see what it does behind the scenes it uses a quality comparer to compare the two contracts with the backing fields so it will check the fields themselves here not actually the references and this is all ties up into the operators overreading here and here and also the hash code is overwritten to return the same thing and then you have the clone method and this clone method is used when you do the width operation i'm going to show that in a second and then you have this protected constructor which is what i talked about it is this secret copy constructor that is used to move from one uh person to the other when you're doing this cloning this copying using the width operator and then you have the deconstruct void method which is used when you deconstruct the record to its properties so this is all that happens behind the scenes and you can see that the compiler team didn't have to change anything other than magically make this change from record to this monster which supports what a record is now let's see what happens when i do use the with operator and i have that here let me just copy it again because i literally can't show you anything here if i paste it again let's go all the way up to see where everything happens so here's what width does it will create a new object using the previous properties that you had when it was originally created and then it will use that clone method that you saw down below and then set each property that you're mutating but you're not really mutating the first one you're just setting it when you create the new one and this is what we will do it will just allow us to use that new name for example here and that's all there is to it this idea of features being added using this process of lowering them into lower levels that the clr already supports is very very common and once you understand it you also understand your code better because you start to put the pieces together and understand how things are made and this helps you with performance and knowledge of the language as well and i hope you learned something in this video well that's all i had for you for this video thank you very much for watching special thanks to my patreons for making these videos possible if you want to support me as well you're going to find it in the link description down below leave a like if you like this video subscribe rocket like this entering the bell as well and i'll see you in the next video keep coding
Info
Channel: Nick Chapsas
Views: 113,472
Rating: undefined out of 5
Keywords: Elfocrash, elfo, coding, .netcore, dot net, core, C#, how to code, tutorial, development, software engineering, microsoft, microsoft mvp, .net core, nick chapsas, chapsas, clean code, dotnet, c# records, record, record c#, c# 9, c# 10, record class, record struct, What are record types in C# and how they actually work
Id: 9v6RENPk5iM
Channel Id: undefined
Length: 15min 36sec (936 seconds)
Published: Thu Dec 30 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.