0:00 - Intro 0:57 - Getting started: demo console app 2:16 - How to use Records 3:45 - Records: declared and explained 6:55 - Record features 13:00 - Records vs. Class: ToString() override 17:04 - Records vs. Class: compare objects 20:49 - Records vs. Class: compare object reference 22:10 - Records vs. Class: compare object == 24:31 - Records vs. Class: object Hash Code 27:10 - Records vs. Class: Recap 28:13 - Records vs. Class: Deconstructor 31:32 - Records vs. Class: Record Object copy 34:30 - About Records 36:19 - Record property access modifier 40:12 - Other Properties in Records 42:53 - Methods in Records 43:56 - Full Properties in Records 47:33 - Recap 49:49 - Record inheritance 52:57 - *Why Records?* 53:53 - /*Benefits*/ 57:45 - /*When to use Records*/ 1:05:10 - /*When not to use Records*/ 1:14:31 - Summary and concluding remarks (+ bonus: top level call args in C# 9) You forgot the time codes ;)
Superman Tim Corey, could not resist getting into yer slipstream. Really great to have you on board. Thanks for yer forte which appears to be a mind boggling easy way to get into web development.
This is amazing; I was recalling concepts from Java Script and Java. It sounds like the smart people at Microsoft worked so hard to make available capabilities that make coding a lot easier. Things that in other languages you just have to remember how to do. But now in C# you have specific methods with specific results. I love it. And you explained it so well as always. Nothing against other languages I love them all, and wish I had time to learn more about them. But I am so glad I decided to learn C# and other Microsoft technologies.
Thanks for such a detailed explanation, Tim. You are the best at explaining complex concepts and having the perfect analogies to better understand them. The house and address analogy for class addresses was brilliant.
Awesome material, and a great explanation! For those trying it at home, there are a couple of syntax simplifications you can use: public record Record2(string FirstName, string LastName) { internal string _firstName = FirstName; internal string FirstName => _firstName.Substring(0, 1); public string FullName => $"{ FirstName } { LastName }"; }
Hi Tim, I'm going to Copenhagen academy in IT learning and I'm doing web programming in server, all my fellow students are more interested in your videos than in our teacher, I post all your free videos on our forum, well done Tim, I also buy your courses and learn a hell of a lot from them many greetings Knud Nielsen Denmark
@@IAmTimCorey I have recommend you to person there start at university study at programming and they are thankfull for your videos, and I wish your lection in Blazor to christmas it's great's
Thanks Tim, I wish you work for MS because your explanations are always crystal clear, unlike MSDN articles which sometime looks like "how to draw Owl" meme.
I'm using records with Dapper now, and it's working out just fine. Then, I have a different approach to data that needs to be changed/updated: I use the copy feature of records. That makes it distinctly clear exactly which fields will be changed. That's a lot more readable than using classes and having to copy every property. Using a record copy exposes clearly what my intentions are, and leaves much less space for bugs to hide in. All my records are still immutable, my code is brief and focused on what I do. it's good :)
Hey Tim, Good stuff, thankyou. Call me crazy but I could swear you said multiple times "location on disk" when differentiating between a record and class You said it so many with confidence it makes me think i'm missing something. (one of us is going crazy :))
I'm not sure if I said disk but I did talk about the physical location of the class instance. That would be the location in memory that is carved out to store your class instance. With a record, when you copy it using the with statement, you are duplicating all of the values into new memory storage. With a class, when you change a value, you are just changing that specific memory value to be something different.
Once I saw a Python talk (I also code in python) and in that talk one thing stuck with me: "Every feature [...] has at least one or two very clear and unambiguous mental models [...] for where is actually useful." The talk was about some python features, like metaclasses, but I found that this thought process can be applied for most of programming in general. I believe is more importante to understand a feature in a abstract level (its mental model/purpose) rather then all the technicalities that you can look up in the documentation. Same goes for records. What is a record, in real life? According to a dictionary: "1. a thing constituting a piece of evidence about the past, especially an account kept in writing or some other permanent form." It stores information about the past. We can't change the past, so we shouldn't change records. So there you go, records are for things that we cannot, or should not, change over time. Those mental models really help me get a hold of when to use certain features.
That's why I believe set shouldn't be valid for records, only init. But I think they've focused too much on the value equality and other stuff and forgot about this
Hi Tim great video as always. I'm watching all yours video and very often you are copying line of the code using copy and paste. I have found very useful to put the cursor on the line that I want to copy and press CTRL+D to copy whole line and paste below. Thank you for sharing your knowledge.
What Luke S just said also works if you select a whole block (say, a method you want copied to make an async version). Oh, and that Ctrl+dot thing on the constructor, to initialize your properties? Try selecting one (or more) properties and hitting Ctrl+dot. It'll ask if you want to initialize it in a constructor... it'll even create the constructor for you if you don't have one yet! :D Saves much typing.
10:30 There's actually an even faster way to do it, you select all the properties that you want in your constructor, then hit alt + enter, there's an option that says generate constructor, it will generate all the constructor for you. You don't have to write anything. I use visual studio 2022 but idk if you can use it in 2019 and below.
Thanks for another great video Tim! At 10:58, what I have also learned from the 'Ctrl + .' boiler plate reduction is you can type your 'firstName' and 'lastName' parameters before typing them as properties. When you 'Ctrl + .' it will give you the option to create the parameters as properties or fields. I have found this helpful in creating DTOs and dependency injection.
Thank you so much for sharing your vast knowledge with us, Mr. Corey! I think I am going to use this records for my DTO objects. This should work fine I guess because I don’t think they (DTOs) should be mutable.
After watching I was dying to check this out: static void Main() { var r1 = new Record1(); var r2 = new Record1(); Debug.Print($"r1: {r1}"); Debug.Print($"r2: {r2}"); Debug.Print($"r1 == r2: {r1 == r2}"); } public record Record1() { public int RandomNumber => new Random().Next(0, 100); } What do you think the last Debug.Print will produce? Take your guess! :D P.S. Thank you Tim for another great video!
Thank you so much for the awesome video! Everything was very well explained! Only thing I was still wondering was if Records can inherit Interfaces or not. I searched the web and I see that they can! :)
At 10:38 of the video when you use the trick to initialize the field value from the constructor, it's even faster if you do Control + Dot on the private field instead of on the parameters of the constructor. In other words have an emty constructor then do Control+Dot on the field and select the option to "Initialize from Constructor". Long video but great thanks Tim
I would add that records are useful when writing more functional code (c# seems to be migrating to be a hybrid language) and if you are using records it should be records and immutability all the way down. A developer can run into issues if a record has a class that is mutable making the record shallow immutable. They do a solid 85% of the work for us but you can still shot yourself in the foot.
"Personality, I wish that classes would do this". Same. For a lot of my classes I simply override ToString() to output a json representation of the class. For the className I simply declare it as a string.
I certainly found the use case for records in our project. For serverside caching, we calculate the SHA256 hashcode of the requests to identify if the request getting repeated, I see records as a potential replacement for classes there as we don't need to change the incoming requests and want the same hashcode every time the same request comes. Scope to get rid of SHA256.
Great video Tim! Very clear like all your others one. Just one small observation! public record User1(int Id, string FirstName, string LastName) : Record1(FirstName, LastName); I think that this line is a bit of confusing because it's the same thing of write: public record User1(int Id, string FirstName, string LastName); The example that would have made the most sense would have been to inherit from Record2 in order to show more clearly that the methods/properties/etc will be inherited too
Your line isn't the same as mine - Record1 has a constructor and we need to pass data into that constructor to satisfy it. So, when we inherit from Record1, we also tell it which two properties to send into Record1's constructor.
Very informative. I did a couple of projects using Akka.Net. Since the objects passed around by Akka must be immutable, records are an excellent way to encapsulate the Akka message data and you don't have to worry about accidentally changing your object.
5:58 - Records act like value types, but they are not 7:44 - Meaning of "init" keyword 8:03 - Records are immutable 17:22 - Records equality 21:04 - Reference equality 23:27 - Equals() and == are not the same 28:19 - Record deconstructor 32:00 - Copying and modifying records
I know this is old but once you override the properties you have to make a constructor and deconstructor for the overridden value for it to retain its original functionality, the reason is you changed it to a non-positional record, similar to how a list works. You told the record I need this to behave differently so it pulled the value from its position does the changes you declare then pops it back at the end as it moves in order. So in your example Last name moves to the front of the order and the changed Firstname moves to a new position behind it. The reason you can use { Get; Set; } is because you need to be able to use them for a public record struct as a struct cant be {get; init; } your case in Do not do is an exploitation of this behavior by hybridizing a loophole. When making the record a struct it takes on the behavior of a value type not a reference type removing the need of immutable. In fact as an example: public record struct Point(float x, float y) //initializes as public struct Point { public float X { get; set; } public float Y { get; set; } public Point(float x, float y) { X = x; Y = y; } } unlike public record Point(float x, float y) //initializes as public class Point { public float X { get; init; } public float Y { get; init; } public Point(float x, float y) { X = x; Y = y; } }
Thanks for all the content you always deliver. I made huge progress in C# over the last year and your videos played a big part on that :) I have two examples where I'm still not sure what I would use: 1. A Coordinate. Usually it was a prime example for a struct. But with all the features of a record, i would tend to create it as a record now. The easy comparison, an easy destructor, immutability and also the ability to have for example a 3DCoordinate inherit from Coordinate. But this makes me wonder, what are cases to use a struct then? (I almost never used structs in the past, do i don't know that much about those) 2. Let's say we have a simple n:1 relationship between city and person (inhabitants) and none of the cities properties will ever change. Just the objects in the Collection for inhabitants. Would it make sense to use a record here, if i want to guarantee immutability?
Great video! Thoroughly enjoyable. I would just like to mention a couple of more use cases that records may be useful for. One thing I especially like about them, is how they can be declared with very little additional boiler plate code. They can be declared almost completely in domain language and they are compact, making them easy to read for non-tech oriented domain experts. They can be used as a tool for defining the domain knowledge in code, and being understandable between domain experts and developers! Another thing they can be really useful for is when combined with the new pattern matching features (Especially switch expressions) - They can be used as a reasonable substitute for discriminated unions, as they are able to be derived from - This, combined with pattern matching is a very powerful combination, and I think would probably warrant its own video. I loved the explanations, and I dont know why MS made the choice to allow mutability.
45:26 Actually, C# will handle way better that we will, TBH. I like the idea of having immutable data philosophy and being closer and closer to functional paradigms in this C# new era. In my opinion, record types comes with lots of extra stuff which is only shadowing what they should be, which is *immutable data structures* . The idea of redeclaring properties and the ability to declare methods makes records less responsable. *Data structures must store data* , nothing more, nothing else. If any system needs to hide some properties from a certain data structure or maybe remapping some of their properties, then the system must do it by itself (by implementing filters, mappers, handlers, etc), not the actual data structure.
Hey Tim, love this video. Totally unrelated but I wanted to let you know that if you do ctrl + enter at the end of a line, it will copy it and put in the next line. I saw you doing a manual copy paste :) Nice shortcut when you want to copy and paste a line. Thanks again for the vid.
I found a case where something should be a record even if there is one property you can write to. Here is a sample case. public record ConnectionInfo(string ConnectionID, string UserID, bool IsConnected) { public bool IsConnected { get; set; } } By still using records, I get the benefits of equality. Plus I get the benefit of having everything in the constructor and if i need to read the values, then i get that benefit as well. There can be many cases where most of the properties are immutable but there is one exception. In that case, I like a person can still use records to still have less boilerplate code.
Don't confuse a need for read-only properties with a need to be a record. A record should be an all or nothing solution. If you need some properties to be read-only, use the "init" keyword instead of set in your properties of a class and it will work the same way. You can also override ToString and the rest to get you where you need to be.
26:48 very dangerous advice here: do not expect 2 objects producing the same hashcode to be equal, that's not a guarantee of the GetHashCode() contract
10:47 this also works vice versa, when you've defined your members like FirstName and LastName already, .-space on an member and you should get the option to create an constructor with parameters. I believe you can even choose which parameters. While ctor only gives blank constructor, this gives you parameterized constructors.
Interesting catch on the use of the internal keyword. Though it should be seen by the declaring class, it's not. Unless M$ considers the declaring class to be the record itself, as it is declared there. But you can sell see it externally, Hmmmmmm. Weird.
Hello Tim, I listened to the whole thing. Very informative, but one last bit you said around 1:13:15 tripped me. You said the record clone is making a shallow copy. But how so? We didn't have any reference types as any properties in the record to begin with. What exactly is shallow copied when you clone a record? Did you mean the reference to the record itself is reused on a clone?
In C# strings are reference types, so in this case when he is creating a new record from a copy of the original and replacing the FirstName value the new instance re-uses the LastName string. This works nicely with multiple levels of records since each instance is immutable so keeping references all over the place as you change only parts of a sub-record is a great performance gain without worrying about state changing underneath you.
the equality checks make records compelling for me. I worked on a project where we kept multiple versions of documents in mongo, so on ingress (creation) we would find an existing, and compare so as to create a new version. Needless to say, we had to override gethashcode based on each of the properties, and then write/maintain equality tests for each such class.
As someone new to C#, but experienced in a number of other frameworks, paradigms, and languages. You spoke in the use cases about the use of these immutable types (Records) when Parallel processing or reference data is being loaded. I can see how you can hard code a Record, but when you have a Data Source (such as the output of an API in JSON or a set of "Objects" from an ORM to your Database via .NET), I can see how I can easily deal with the ingestion of those into a Class, but can Records be the subject of an ORM easily or do I have to unravel things from a class that duplicates the content that I'm interested in -- inheritance from Class to Record would seem to be a logical way to bridge this. At the end you use composition with the Class having a Record, can that be the subject of an Object Relational Mapping without a ton of manual assignments? Awesome quality and detailed dive into Records, I'll be on the look out for other subjects on RUclips and take a look at the courses you mentioned. I may have typed too soon. You mentioned "Dapper" in your Don't section and EF is not working yet. You see I would like to have an Add/Change/Delete C# App to maintain my massive DataSet and then have Records in my Analysis App with a way to share definition of the Database Access to help with changes between the two. Anyhow, any insight you can impart would get great or another Video would be even better :^)
Well, my video introducing Dapper will help you: ruclips.net/video/Et2khGnrIqc/видео.html (I also have an Advanced Dapper video if needed). I'll be showing off Records more soon (probably in next week's video, for example).
Hi Tim! Great video as always! While you were showing that bug you found in the overridden "ToString()" method in record types, I think it only works with public properties because records might be using the Reflection API (which by default only "sees" public properties). I don't actually know if that's it (didn't find anything on the web related to it), but that might be the case since one of the changes in .NET 5 was to port a lot of the runtime to C# code, so they might be using it more often, specially with something that's new and was probably written in native code! And if it is intentional, it makes sense (at least to me) because I don't understand the use of objects that are supposed to be immutable having non-public properties and a lot of "heavy business logic" inside it, so a property's access level might influence other parts of the record and operations related to it, like the "ToString()" override. Thank you for the videos you make, helps me a lot to stay in touch with the cutting-edge stuff related to C#.
@ IAmTimCorey I like using record's when working with Json (System.Text.Json). I write a record that describe my format, then I serialize and desterilize it when needed. Also, I like using the custom Deconstruct void in my record to do Pattern Matching.(Fun Stuff)
around minute 40: the automatic ToString() construction actually behaves quite good there... it only contains public members... i would have been afraid if it leaked internal or even private content there... sure, internal is an edge case here, since it behaves like public in the same assembly and like protected in other assemblies... they had to make a decision here: behave consistently or differently depending from where ToString() is called... i think it's a good thing they decided to always only include public members in the automatic ToString(), since otherwise the behaviour of ToString() would change depending on from where it is called... and that's rarely a good thing 🤗
I have one Question. What the Name of the PlugIn, that show the Parameter-Names inside the code. Example: Record r1a = new (Firstname: "Tim", Lastname: "Corey); -> I mean the Firstname and Lastname inside the constructor?
I have a few questions that was not answered? First, can you use generics? Also, can records implement interfaces? There is one major problem with them though. How would they work with dependency injection. Because many objects you have to depend on other services and add extra stuff. There was one very good use for records that was not discussed. Records is actually good for change tracking. I found a case where for blazor for example where it needs to know whether to render, at first, i override the afterrender and create a record. Then for shouldrender, i create a record again. In that case, its easy comparison. For anything that changed, if false, then shouldrender is true which helps in performance. that was not possible with classes. Also, i found a case where there was a warning not to do something but has another use case to do it anyways. The sample is something like this. public record Person(string FirstName, string LastName) { public string FirstName { get; set; } = FirstName; public string LastName { get; set; } = LastName; } class Program { static void Main(string[] args) { Person person1 = new Person("Test", "Walter"); Person person2 = new Person("Test", "Walter"); person2.FirstName = "Bob"; person2.FirstName = "Test"; Console.WriteLine(person1 == person2); Console.WriteLine(person1); var (f, l) = person1; Console.WriteLine(f); Console.WriteLine(l); } } In this case, you get all the benefits of records but is still mutable. Obviously the thread safe a person would not get. However, you get the benefit of tostring. Plus the benefit of deconstruction. Finally the benefit of equality. One very good use of records is if you need equality based on values and not just reference for cases where something needs to know if anything changed.
I am not sure what you mean by "can you use generics". We can use a record in a generic and we can have a method that takes in a generic in a record. Remember that it is just a class with extra stuff. That same rule applies to the question about interfaces. Yes, because a class can implement interfaces. I would be interested to see if that record comparison actually saves any cycles in the rendering process and, if so, how many. Making a record mutable is not a wise idea. There are more implications to changing records to a mutable type. Like you stated, it can cause serious problems with asynchronous programming. There is also an issue with the hash code changing when the expectation is that it will stay the same. But the biggest problem, though, is that records are designed to be immutable. By making them mutable, you break the common assumption of records. That can introduce bugs in your code later, when you or someone else assumes immutability. This is one of those cases where you can do something but you probably should not do it.
@@IAmTimCorey Actually record comparison saves a lot. For example, I was working on a game called heap solitiare for blazor. Before records, what would happen is it would rerender all the cards which makes it very slow when selecting something. By using record comparison, for shouldrender, it would know even though the reference is different, the values are the same so its the same. Therefore, it will not render. That made all the difference between having high performance and being too slow.
I'm not sure about 1 part regarding inheritance: For example there is base Employee record and its derived record Manager. If I write Person p = new Manager(...); As expected I dont have access to Manager members untill I do explicit cast, but. Why p.ToString() prints Manager and even its members in {}, instead of Person? I have only guesses. Is it overrides ToString at runtime or even implicitly converts whole p instance ?
As the Model or the ViewModel? If the model then it could be as long as you don't manipulate the data coming in or going out. It would not really work as the ViewModel because the VM inherits from a class and it allows for data change.
After experimenting, I found I am able to implement interfaces. However, when I use the dependency injection for blazor using records, I actually get a runtime error even though i am only using properties. Hopefully there is a way to fix that case because its actually very common for somebody to create an interface for models and implement the interface for models even if its readonly models.
I am not picturing what you are trying to do. You put an interface on your model (that's not terribly common - you only need to do that if you are replacing logic. Otherwise, you can use a base class.) and then you tried to instantiate it in dependency injection? That won't work. Remember that records are immutable. Once you instantiate them, they don't change. So if your dependency injection system instantiated a record and then gave it to you, the best-case scenario would be that it was blank. If you use the common syntax, it would fail because it would not be provided the correct number of property values.
@@SaitamaTheLegend For the case where i used interfaces is i have a music app program that i created. However, there can be multiple music databases though and the structure of each is different. However, I wanted to have shared code for the program. So for the interface, everything that was in common, became an interface. An example is i have an interface with this code. public interface IPlaySong { int ID { get; set; } string SongName { get; set; } string ArtistName { get; set; } //not has to allow writing because dapper is different. string FullPath { get; } int Length { get; set; } int SongNumber { get; set; } string GetSongArtistDisplay(); //i think we still need this one. } Then i have 2 implementations. For each of them, the table names are different. Plus how they map are different as well. So in the base classes, they just know you need to somehow get the information so it can work with any music system regardless of how its stored even. At the time I was learning interfaces, I actually thought that everything should start with interfaces and then implementing them. In many cases the idea worked because I was able to mock classes and was even able to fix a few of my hidden bugs that way.
@@SaitamaTheLegend For my case I actually switched to dapper. After watching tim coreys videos about dapper, i redid my music processes to use dapper. I even created my own dapper helpers so i still don't have to use raw sql. At the time, I chose interfaces because i sometimes ran into troubles with classes because you can't inherit from more than one. In my system, I do sometimes have more than one music class. To make it easier to organize, I did interfaces so the 2 systems are not related except for the interface contract. The only time that di was used was for creating a new object. even with abstract classes, that would be required because a person cannot new up a brand new abstract class either. I even ended up creating my own dependency injection system as well.
@@SaitamaTheLegend I actually created a repository that is public for my entire music system. Its here github.com/musictopia2/MediaHelpersCP This has all cross platform stuff. Of course, I have a private library for my implementation. This was designed to be able to create many different music systems and still use shared code. Uses lots of interfaces so does not care how things are done.
Great video as always! just got around to learning this. 1 quick question - where would you define those records? in classes, we usually define each class in its own file is this the same for records?
@@IAmTimCorey is there a way to capture all of these after video creation knowledge into the description? I knew someone would have an answer to this but I had to skim past several comments to get an answer.
Thank you Tim, seriously this is the first time I know about Records in .Net core.
Please give us all updates in C# as much as you can.
Records are brand new, so you haven't been missing anything. They were just released in November 2020.
0:00 - Intro
0:57 - Getting started: demo console app
2:16 - How to use Records
3:45 - Records: declared and explained
6:55 - Record features
13:00 - Records vs. Class: ToString() override
17:04 - Records vs. Class: compare objects
20:49 - Records vs. Class: compare object reference
22:10 - Records vs. Class: compare object ==
24:31 - Records vs. Class: object Hash Code
27:10 - Records vs. Class: Recap
28:13 - Records vs. Class: Deconstructor
31:32 - Records vs. Class: Record Object copy
34:30 - About Records
36:19 - Record property access modifier
40:12 - Other Properties in Records
42:53 - Methods in Records
43:56 - Full Properties in Records
47:33 - Recap
49:49 - Record inheritance
52:57 - *Why Records?*
53:53 - /*Benefits*/
57:45 - /*When to use Records*/
1:05:10 - /*When not to use Records*/
1:14:31 - Summary and concluding remarks (+ bonus: top level call args in C# 9)
You forgot the time codes ;)
Yeah. U took a LOT of time to do it, when Tim already knew the times...
Thanks! MUCH appreciated
Superman Tim Corey, could not resist getting into yer slipstream. Really great to have you on board. Thanks for yer forte which appears to be a mind boggling easy way to get into web development.
Thank you for the support!
This is amazing; I was recalling concepts from Java Script and Java. It sounds like the smart people at Microsoft worked so hard to make available capabilities that make coding a lot easier. Things that in other languages you just have to remember how to do. But now in C# you have specific methods with specific results. I love it. And you explained it so well as always. Nothing against other languages I love them all, and wish I had time to learn more about them. But I am so glad I decided to learn C# and other Microsoft technologies.
Thanks for watching and sharing!
Thanks for such a detailed explanation, Tim. You are the best at explaining complex concepts and having the perfect analogies to better understand them. The house and address analogy for class addresses was brilliant.
You're very welcome!
Awesome material, and a great explanation!
For those trying it at home, there are a couple of syntax simplifications you can use:
public record Record2(string FirstName, string LastName)
{
internal string _firstName = FirstName;
internal string FirstName => _firstName.Substring(0, 1);
public string FullName => $"{ FirstName } { LastName }";
}
Thanks for the tips!
Thank you so much Tim, records definitely needed their own video.
Very welcome
Great, in my humble opinion, i think you deserve the c# crown
Thank you!
Hi Tim, I'm going to Copenhagen academy in IT learning and I'm doing web programming in server, all my fellow students are more interested in your videos than in our teacher, I post all your free videos on our forum, well done Tim, I also buy your courses and learn a hell of a lot from them many greetings Knud Nielsen Denmark
Awesome! I am glad they have been so helpful.
@@IAmTimCorey I have recommend you to person there start at university study at programming and they are thankfull for your videos, and I wish your lection in Blazor to christmas it's great's
Thanks Tim, I wish you work for MS because your explanations are always crystal clear, unlike MSDN articles which sometime looks like "how to draw Owl" meme.
You are very welcome.
Thank you very much for this valuable knowledge.
My pleasure
I will definitely reference this video to my colleagues
Sir, I love the way you teach.
Thanks!
I'm using records with Dapper now, and it's working out just fine.
Then, I have a different approach to data that needs to be changed/updated: I use the copy feature of records. That makes it distinctly clear exactly which fields will be changed. That's a lot more readable than using classes and having to copy every property. Using a record copy exposes clearly what my intentions are, and leaves much less space for bugs to hide in.
All my records are still immutable, my code is brief and focused on what I do. it's good :)
Hey Tim, Good stuff, thankyou. Call me crazy but I could swear you said multiple times "location on disk" when differentiating between a record and class You said it so many with confidence it makes me think i'm missing something. (one of us is going crazy :))
I'm not sure if I said disk but I did talk about the physical location of the class instance. That would be the location in memory that is carved out to store your class instance. With a record, when you copy it using the with statement, you are duplicating all of the values into new memory storage. With a class, when you change a value, you are just changing that specific memory value to be something different.
@@IAmTimCorey Yes, i know.... but you said "location on disk like 5 times". No worries. Will be interesting to see how this new Record thingy is used.
@@IAmTimCorey Well... perhaps not 5 times, but for sure 2 or 3 at least. You can hear an example of this at 24:11.
I was also wondering about this. Glad Tim replied to clarify it wasn't intentional.
Once I saw a Python talk (I also code in python) and in that talk one thing stuck with me:
"Every feature [...] has at least one or two very clear and unambiguous mental models [...] for where is actually useful."
The talk was about some python features, like metaclasses, but I found that this thought process can be applied for most of programming in general. I believe is more importante to understand a feature in a abstract level (its mental model/purpose) rather then all the technicalities that you can look up in the documentation. Same goes for records. What is a record, in real life? According to a dictionary:
"1. a thing constituting a piece of evidence about the past, especially an account kept in writing or some other permanent form."
It stores information about the past. We can't change the past, so we shouldn't change records. So there you go, records are for things that we cannot, or should not, change over time. Those mental models really help me get a hold of when to use certain features.
That's why I believe set shouldn't be valid for records, only init.
But I think they've focused too much on the value equality and other stuff and forgot about this
You don’t update the number of victims when the serial killer strikes again?
I think we need to update his record.
😎
There'll be a new record of a new crime. No past records would change
Nicely done, thanks for sharing
More people need to watch this video!! I was having a hard time understanding records and this cleared everything up!
Excellent!
Hi Tim great video as always. I'm watching all yours video and very often you are copying line of the code using copy and paste. I have found very useful to put the cursor on the line that I want to copy and press CTRL+D to copy whole line and paste below. Thank you for sharing your knowledge.
What Luke S just said also works if you select a whole block (say, a method you want copied to make an async version).
Oh, and that Ctrl+dot thing on the constructor, to initialize your properties? Try selecting one (or more) properties and hitting Ctrl+dot. It'll ask if you want to initialize it in a constructor... it'll even create the constructor for you if you don't have one yet! :D
Saves much typing.
Yep, I just forget that shortcut since I use it so infrequently (mostly just for demos).
Thank you very much for this valuable knowledge.
Records - A value-added to C#
You are welcome!
बहुत ही अच्छा वीडियो टीम जी आप ऐसा ही ज्ञानपुर्वक वीडियो हमारे लिए लाते रहिए । हमारी दुआ आपके साथ है । धन्यवाद 🙏
बहुत-बहुत धन्यवाद
10:30 There's actually an even faster way to do it, you select all the properties that you want in your constructor, then hit alt + enter, there's an option that says generate constructor, it will generate all the constructor for you. You don't have to write anything. I use visual studio 2022 but idk if you can use it in 2019 and below.
Thanks for sharing!
Thanks a lot for this amazing video! You should definitely get used to the "Ctrl+D" shortcut tho :D
Glad it helped!
Thanks for another great video Tim! At 10:58, what I have also learned from the 'Ctrl + .' boiler plate reduction is you can type your 'firstName' and 'lastName' parameters before typing them as properties. When you 'Ctrl + .' it will give you the option to create the parameters as properties or fields. I have found this helpful in creating DTOs and dependency injection.
Great tip!
Thank you so much Tim, no matter what level a developer is, ur uploads are great !
Glad you like them!
Great educational presentation with high quality! And the chapter breakdown makes it easy to jump between the parts you find most useful.
Glad it was helpful! Give Ralfs thanks for the timestamps. He has done dozens of videos as a way to give back to this great community of viewers.
Thanks Tim, I knew I could only get vivid description of the updates from you. Looking forward to the Blazor updates.
More to come!
Perfect timing, as I head for my lunchtime coffee !
Worried about 1:19:44 long coffee break 😀😂 just joking
Yes, it does sound like a LOT of coffee.
Oh my god, this video contains huge amount of infomation. Thanks a million!
Glad it was helpful!
Thank you so much for sharing your vast knowledge with us, Mr. Corey! I think I am going to use this records for my DTO objects. This should work fine I guess because I don’t think they (DTOs) should be mutable.
You are welcome.
After watching I was dying to check this out:
static void Main()
{
var r1 = new Record1();
var r2 = new Record1();
Debug.Print($"r1: {r1}");
Debug.Print($"r2: {r2}");
Debug.Print($"r1 == r2: {r1 == r2}");
}
public record Record1()
{
public int RandomNumber => new Random().Next(0, 100);
}
What do you think the last Debug.Print will produce? Take your guess! :D
P.S. Thank you Tim for another great video!
Thank you so much for the awesome video! Everything was very well explained! Only thing I was still wondering was if Records can inherit Interfaces or not. I searched the web and I see that they can! :)
Yep, records are classes so they can implement interfaces or inherit from other records.
34:43 Difference between struct and record
36:02 Records can have methods and can inherit from other records
52:59 Why we need records
Thank you very much TimCorey you explain very well.
I guess we also can use records for const variables
They won't provide you the same benefits as a const, but they are read-only (mostly).
You forgot your fav. Putting records in lists.
It works.
Thanks for the video :)
Also 11:57
ctrl+d.
Yeah, I always forget the line duplication shortcut. I only use it in demos.
Wow, I missed the ability to omit a type during instantiation in c# 9. That's nice, my eyes crossed when you first used it.
Good stuff!
Timestamp please?
At 10:38 of the video when you use the trick to initialize the field value from the constructor, it's even faster if you do Control + Dot on the private field instead of on the parameters of the constructor. In other words have an emty constructor then do Control+Dot on the field and select the option to "Initialize from Constructor". Long video but great thanks Tim
Yep, that works too.
I would add that records are useful when writing more functional code (c# seems to be migrating to be a hybrid language) and if you are using records it should be records and immutability all the way down.
A developer can run into issues if a record has a class that is mutable making the record shallow immutable. They do a solid 85% of the work for us but you can still shot yourself in the foot.
It is possible. Thanks for sharing.
Thank you Tim for this awesome content. The comment section is educational as well.
You are welcome.
Excellente video indeed. Everything was thoroughly explained. Thank you!
You are welcome.
"Personality, I wish that classes would do this".
Same. For a lot of my classes I simply override ToString() to output a json representation of the class. For the className I simply declare it as a string.
Maybe someday.
I certainly found the use case for records in our project. For serverside caching, we calculate the SHA256 hashcode of the requests to identify if the request getting repeated, I see records as a potential replacement for classes there as we don't need to change the incoming requests and want the same hashcode every time the same request comes. Scope to get rid of SHA256.
Nice!
Great video Tim! Very clear like all your others one.
Just one small observation!
public record User1(int Id, string FirstName, string LastName) : Record1(FirstName, LastName);
I think that this line is a bit of confusing because it's the same thing of write:
public record User1(int Id, string FirstName, string LastName);
The example that would have made the most sense would have been to inherit from Record2 in order to show more clearly that the methods/properties/etc will be inherited too
Your line isn't the same as mine - Record1 has a constructor and we need to pass data into that constructor to satisfy it. So, when we inherit from Record1, we also tell it which two properties to send into Record1's constructor.
Very informative. I did a couple of projects using Akka.Net. Since the objects passed around by Akka must be immutable, records are an excellent way to encapsulate the Akka message data and you don't have to worry about accidentally changing your object.
Thanks for sharing
5:58 - Records act like value types, but they are not
7:44 - Meaning of "init" keyword
8:03 - Records are immutable
17:22 - Records equality
21:04 - Reference equality
23:27 - Equals() and == are not the same
28:19 - Record deconstructor
32:00 - Copying and modifying records
Woah as you said new shiny stuff, but "why"... I liked that you answered that question. Great Video
Glad you liked it!
I know this is old but once you override the properties you have to make a constructor and deconstructor for the overridden value for it to retain its original functionality, the reason is you changed it to a non-positional record, similar to how a list works. You told the record I need this to behave differently so it pulled the value from its position does the changes you declare then pops it back at the end as it moves in order. So in your example Last name moves to the front of the order and the changed Firstname moves to a new position behind it.
The reason you can use { Get; Set; } is because you need to be able to use them for a public record struct as a struct cant be {get; init; } your case in Do not do is an exploitation of this behavior by hybridizing a loophole. When making the record a struct it takes on the behavior of a value type not a reference type removing the need of immutable.
In fact as an example:
public record struct Point(float x, float y) //initializes as
public struct Point
{
public float X { get; set; }
public float Y { get; set; }
public Point(float x, float y)
{
X = x; Y = y;
}
}
unlike public record Point(float x, float y) //initializes as
public class Point
{
public float X { get; init; }
public float Y { get; init; }
public Point(float x, float y)
{
X = x; Y = y;
}
}
Great video and Thanks for the detailed explanation Tim....
You bet
Thanks for all the content you always deliver. I made huge progress in C# over the last year and your videos played a big part on that :)
I have two examples where I'm still not sure what I would use:
1. A Coordinate. Usually it was a prime example for a struct. But with all the features of a record, i would tend to create it as a record now. The easy comparison, an easy destructor, immutability and also the ability to have for example a 3DCoordinate inherit from Coordinate. But this makes me wonder, what are cases to use a struct then? (I almost never used structs in the past, do i don't know that much about those)
2. Let's say we have a simple n:1 relationship between city and person (inhabitants) and none of the cities properties will ever change. Just the objects in the Collection for inhabitants. Would it make sense to use a record here, if i want to guarantee immutability?
Tim Sharp Corey 👍👌
Thanks
Hi, I was looking for a spread operator in C#, I think record just fit with the Blazor-state. Great tutorials, thanks.
You are welcome.
Thank you Tim! This is a high quality Knowledge.!
My pleasure!
Thanks Tim, this is a great video!
Glad you liked it!
Great video! Thoroughly enjoyable. I would just like to mention a couple of more use cases that records may be useful for. One thing I especially like about them, is how they can be declared with very little additional boiler plate code. They can be declared almost completely in domain language and they are compact, making them easy to read for non-tech oriented domain experts. They can be used as a tool for defining the domain knowledge in code, and being understandable between domain experts and developers! Another thing they can be really useful for is when combined with the new pattern matching features (Especially switch expressions) - They can be used as a reasonable substitute for discriminated unions, as they are able to be derived from - This, combined with pattern matching is a very powerful combination, and I think would probably warrant its own video. I loved the explanations, and I dont know why MS made the choice to allow mutability.
Thanks for sharing
Great video, many thanks Tim! I'm definitely going to recommend your videos to my co-workers.
Please do!
45:26 Actually, C# will handle way better that we will, TBH.
I like the idea of having immutable data philosophy and being closer and closer to functional paradigms in this C# new era.
In my opinion, record types comes with lots of extra stuff which is only shadowing what they should be, which is *immutable data structures* . The idea of redeclaring properties and the ability to declare methods makes records less responsable.
*Data structures must store data* , nothing more, nothing else.
If any system needs to hide some properties from a certain data structure or maybe remapping some of their properties, then the system must do it by itself (by implementing filters, mappers, handlers, etc), not the actual data structure.
Thanks Tim! Would be great if you could condense these to 20 min max. Trying to watch this using 2x but it still feels slow.
That is what his 10 minutes series is intended to address - ruclips.net/video/yIXqn1L7p_4/видео.html
Hey Tim, love this video. Totally unrelated but I wanted to let you know that if you do ctrl + enter at the end of a line, it will copy it and put in the next line. I saw you doing a manual copy paste :) Nice shortcut when you want to copy and paste a line. Thanks again for the vid.
Great tip!
I found a case where something should be a record even if there is one property you can write to. Here is a sample case.
public record ConnectionInfo(string ConnectionID, string UserID, bool IsConnected)
{
public bool IsConnected { get; set; }
}
By still using records, I get the benefits of equality. Plus I get the benefit of having everything in the constructor and if i need to read the values, then i get that benefit as well. There can be many cases where most of the properties are immutable but there is one exception. In that case, I like a person can still use records to still have less boilerplate code.
Don't confuse a need for read-only properties with a need to be a record. A record should be an all or nothing solution. If you need some properties to be read-only, use the "init" keyword instead of set in your properties of a class and it will work the same way. You can also override ToString and the rest to get you where you need to be.
26:48 very dangerous advice here: do not expect 2 objects producing the same hashcode to be equal, that's not a guarantee of the GetHashCode() contract
Wow, its a real deep dive in to record.. I wondering what is a way to use a record in foreach or for loop?
Sure, it works just like any class.
Great explanation of records in C# 9!
Thanks Tim
You are welcome.
Great Tutorial. I enjoyed it and got a lot out of it.
Thanks for following Tim
Huge addition to C#, introduced with a great video!
Thank you!
You're very welcome!
Very informative video. Other resources and even books don't cover that much about records!
Thank you for the big fonts.
You are welcome.
thanks Tim for the time and effort , try using CTR+D to duplicate lines in vs
Cool! I didn’t know that.
I have vsVim installed and I do yy p
🥸
Good tip!
☝🏾🔥👍🏽
That is a very good deep dive into records.
Thanks!
10:47 this also works vice versa, when you've defined your members like FirstName and LastName already, .-space on an member and you should get the option to create an constructor with parameters. I believe you can even choose which parameters. While ctor only gives blank constructor, this gives you parameterized constructors.
Nice!
Interesting catch on the use of the internal keyword. Though it should be seen by the declaring class, it's not. Unless M$ considers the declaring class to be the record itself, as it is declared there. But you can sell see it externally, Hmmmmmm. Weird.
Hello Tim, I listened to the whole thing. Very informative, but one last bit you said around 1:13:15 tripped me. You said the record clone is making a shallow copy. But how so? We didn't have any reference types as any properties in the record to begin with. What exactly is shallow copied when you clone a record? Did you mean the reference to the record itself is reused on a clone?
In C# strings are reference types, so in this case when he is creating a new record from a copy of the original and replacing the FirstName value the new instance re-uses the LastName string. This works nicely with multiple levels of records since each instance is immutable so keeping references all over the place as you change only parts of a sub-record is a great performance gain without worrying about state changing underneath you.
Great as always, thank you Mr. Corey! So records are immutable unless you add setters and make them mutable, got it :-).
Thanks for watching!
This is a very cool feature. So many duplicated code can be saved by a simple keyword.
Glad you like it.
the equality checks make records compelling for me. I worked on a project where we kept multiple versions of documents in mongo, so on ingress (creation) we would find an existing, and compare so as to create a new version. Needless to say, we had to override gethashcode based on each of the properties, and then write/maintain equality tests for each such class.
That sounds like a good option.
As someone new to C#, but experienced in a number of other frameworks, paradigms, and languages. You spoke in the use cases about the use of these immutable types (Records) when Parallel processing or reference data is being loaded. I can see how you can hard code a Record, but when you have a Data Source (such as the output of an API in JSON or a set of "Objects" from an ORM to your Database via .NET), I can see how I can easily deal with the ingestion of those into a Class, but can Records be the subject of an ORM easily or do I have to unravel things from a class that duplicates the content that I'm interested in -- inheritance from Class to Record would seem to be a logical way to bridge this. At the end you use composition with the Class having a Record, can that be the subject of an Object Relational Mapping without a ton of manual assignments?
Awesome quality and detailed dive into Records, I'll be on the look out for other subjects on RUclips and take a look at the courses you mentioned.
I may have typed too soon. You mentioned "Dapper" in your Don't section and EF is not working yet. You see I would like to have an Add/Change/Delete C# App to maintain my massive DataSet and then have Records in my Analysis App with a way to share definition of the Database Access to help with changes between the two. Anyhow, any insight you can impart would get great or another Video would be even better :^)
Well, my video introducing Dapper will help you: ruclips.net/video/Et2khGnrIqc/видео.html (I also have an Advanced Dapper video if needed). I'll be showing off Records more soon (probably in next week's video, for example).
@@IAmTimCorey Much appreciated!
Hi Tim! Great video as always!
While you were showing that bug you found in the overridden "ToString()" method in record types, I think it only works with public properties because records might be using the Reflection API (which by default only "sees" public properties). I don't actually know if that's it (didn't find anything on the web related to it), but that might be the case since one of the changes in .NET 5 was to port a lot of the runtime to C# code, so they might be using it more often, specially with something that's new and was probably written in native code!
And if it is intentional, it makes sense (at least to me) because I don't understand the use of objects that are supposed to be immutable having non-public properties and a lot of "heavy business logic" inside it, so a property's access level might influence other parts of the record and operations related to it, like the "ToString()" override.
Thank you for the videos you make, helps me a lot to stay in touch with the cutting-edge stuff related to C#.
Yep, I discovered that later in the video and yes, it makes sense to not expose something accidentally.
Absolutely top content Tim!! More power to you
Thank you!
@
IAmTimCorey
I like using record's when working with Json (System.Text.Json). I write a record that describe my format, then I serialize and desterilize it when needed. Also, I like using the custom Deconstruct void in my record to do Pattern Matching.(Fun Stuff)
Great!
It's nice to see some of the best features of F# making it's way into C#.
Thank you for this awesome C# Record.
You are welcome.
I really thank you for this video tutorial
Glad it was helpful!
10:45 Going one step further, you can use "control dot" to create the property or field from the constructor too, instead of creating them by hand.
Thanks for the Tip
around minute 40:
the automatic ToString() construction actually behaves quite good there... it only contains public members... i would have been afraid if it leaked internal or even private content there... sure, internal is an edge case here, since it behaves like public in the same assembly and like protected in other assemblies... they had to make a decision here: behave consistently or differently depending from where ToString() is called... i think it's a good thing they decided to always only include public members in the automatic ToString(), since otherwise the behaviour of ToString() would change depending on from where it is called... and that's rarely a good thing 🤗
Good points.
I have one Question. What the Name of the PlugIn, that show the Parameter-Names inside the code. Example: Record r1a = new (Firstname: "Tim", Lastname: "Corey); -> I mean the Firstname and Lastname inside the constructor?
docs.microsoft.com/en-us/visualstudio/ide/reference/options-text-editor-csharp-advanced?view=vs-2019#editor-help
Watch my previous video, where I introduce 5 new features of C# 9. I show how to turn that on.
excellent work in this video, thanks
You are welcome.
Many thanks for this video.
I have a couple of queries:
1. Can we place records in a list?
2. Can we use them in as Models in MVVM (E.G. PersonModel)?
Yes, and yes.
@@phizc Thank you.
Vemund is correct, although typically in MVVM you want to make changes to your model. In that case, you would want to use a class.
@@IAmTimCorey Many thanks. That confirms what I thought.
I think records are good candidate for dictionary keys
40:00 - I have found that it works this way: public string Name { internal get; init; } = Name;
Really great explanation!
Thanks!
Wonderful explanation, very useful, thank you so much!
Glad it was helpful!
@@IAmTimCorey I've learned a lot from your videos, you really are a great teacher. Greetings from Italy!
I have a few questions that was not answered? First, can you use generics? Also, can records implement interfaces? There is one major problem with them though. How would they work with dependency injection. Because many objects you have to depend on other services and add extra stuff. There was one very good use for records that was not discussed. Records is actually good for change tracking. I found a case where for blazor for example where it needs to know whether to render, at first, i override the afterrender and create a record. Then for shouldrender, i create a record again. In that case, its easy comparison. For anything that changed, if false, then shouldrender is true which helps in performance. that was not possible with classes. Also, i found a case where there was a warning not to do something but has another use case to do it anyways. The sample is something like this.
public record Person(string FirstName, string LastName)
{
public string FirstName { get; set; } = FirstName;
public string LastName { get; set; } = LastName;
}
class Program
{
static void Main(string[] args)
{
Person person1 = new Person("Test", "Walter");
Person person2 = new Person("Test", "Walter");
person2.FirstName = "Bob";
person2.FirstName = "Test";
Console.WriteLine(person1 == person2);
Console.WriteLine(person1);
var (f, l) = person1;
Console.WriteLine(f);
Console.WriteLine(l);
}
}
In this case, you get all the benefits of records but is still mutable. Obviously the thread safe a person would not get. However, you get the benefit of tostring. Plus the benefit of deconstruction. Finally the benefit of equality. One very good use of records is if you need equality based on values and not just reference for cases where something needs to know if anything changed.
I am not sure what you mean by "can you use generics". We can use a record in a generic and we can have a method that takes in a generic in a record. Remember that it is just a class with extra stuff. That same rule applies to the question about interfaces. Yes, because a class can implement interfaces.
I would be interested to see if that record comparison actually saves any cycles in the rendering process and, if so, how many.
Making a record mutable is not a wise idea. There are more implications to changing records to a mutable type. Like you stated, it can cause serious problems with asynchronous programming. There is also an issue with the hash code changing when the expectation is that it will stay the same. But the biggest problem, though, is that records are designed to be immutable. By making them mutable, you break the common assumption of records. That can introduce bugs in your code later, when you or someone else assumes immutability.
This is one of those cases where you can do something but you probably should not do it.
@@IAmTimCorey Actually record comparison saves a lot. For example, I was working on a game called heap solitiare for blazor. Before records, what would happen is it would rerender all the cards which makes it very slow when selecting something. By using record comparison, for shouldrender, it would know even though the reference is different, the values are the same so its the same. Therefore, it will not render. That made all the difference between having high performance and being too slow.
I'm not sure about 1 part regarding inheritance: For example there is base Employee record and its derived record Manager. If I write Person p = new Manager(...); As expected I dont have access to Manager members untill I do explicit cast, but. Why p.ToString() prints Manager and even its members in {}, instead of Person? I have only guesses. Is it overrides ToString at runtime or even implicitly converts whole p instance ?
Correct me if I'm wrong here: would a MVC ViewModel be a good place to use Records?
As the Model or the ViewModel? If the model then it could be as long as you don't manipulate the data coming in or going out. It would not really work as the ViewModel because the VM inherits from a class and it allows for data change.
@@IAmTimCorey my bad, yes I did mean the @model declaration at the top of the page. Secondary lesson of the day View's Model is not a ViewModel.
Excelente video, the only observation I see is that if records are basically classes with add in functionality, how they interact with interfaces?
You can use interfaces as normal. Just make sure any init properties are get only in the interface.
After experimenting, I found I am able to implement interfaces. However, when I use the dependency injection for blazor using records, I actually get a runtime error even though i am only using properties. Hopefully there is a way to fix that case because its actually very common for somebody to create an interface for models and implement the interface for models even if its readonly models.
I am not picturing what you are trying to do. You put an interface on your model (that's not terribly common - you only need to do that if you are replacing logic. Otherwise, you can use a base class.) and then you tried to instantiate it in dependency injection? That won't work. Remember that records are immutable. Once you instantiate them, they don't change. So if your dependency injection system instantiated a record and then gave it to you, the best-case scenario would be that it was blank. If you use the common syntax, it would fail because it would not be provided the correct number of property values.
@@SaitamaTheLegend For the case where i used interfaces is i have a music app program that i created. However, there can be multiple music databases though and the structure of each is different. However, I wanted to have shared code for the program. So for the interface, everything that was in common, became an interface. An example is i have an interface with this code.
public interface IPlaySong
{
int ID { get; set; }
string SongName { get; set; }
string ArtistName { get; set; } //not has to allow writing because dapper is different.
string FullPath { get; }
int Length { get; set; }
int SongNumber { get; set; }
string GetSongArtistDisplay(); //i think we still need this one.
}
Then i have 2 implementations. For each of them, the table names are different. Plus how they map are different as well. So in the base classes, they just know you need to somehow get the information so it can work with any music system regardless of how its stored even. At the time I was learning interfaces, I actually thought that everything should start with interfaces and then implementing them. In many cases the idea worked because I was able to mock classes and was even able to fix a few of my hidden bugs that way.
@@SaitamaTheLegend For my case I actually switched to dapper. After watching tim coreys videos about dapper, i redid my music processes to use dapper. I even created my own dapper helpers so i still don't have to use raw sql. At the time, I chose interfaces because i sometimes ran into troubles with classes because you can't inherit from more than one. In my system, I do sometimes have more than one music class. To make it easier to organize, I did interfaces so the 2 systems are not related except for the interface contract. The only time that di was used was for creating a new object. even with abstract classes, that would be required because a person cannot new up a brand new abstract class either. I even ended up creating my own dependency injection system as well.
@@SaitamaTheLegend I actually created a repository that is public for my entire music system. Its here github.com/musictopia2/MediaHelpersCP This has all cross platform stuff. Of course, I have a private library for my implementation. This was designed to be able to create many different music systems and still use shared code. Uses lots of interfaces so does not care how things are done.
Great video. Thanks a lot!
You are welcome.
Is there a way to force in a project, that all records wil be fully immutable? I meant, lke not allowing having mutable fields in the record...
You can do that with Analyzers. I don't know if anyone's made one yet, but it wouldn't be hard.
It is not baked-in yet. I would like that feature as well.
@@IAmTimCorey would you volunteer submitting such a feature request?
Microsoft should hire you Tim 😉
I'm enjoying being independent.
r1d = r1d with { FirstName = "Blah" }; // Mutates in place (sorta,.. the reference changes). Could be useful. Could also be dangerous.
Great video as always!
just got around to learning this.
1 quick question - where would you define those records?
in classes, we usually define each class in its own file
is this the same for records?
It depends. I like them to have their own file, but sometimes it doesn't make sense.
@IAmTimCorey would you be kind enough to make us a video on the differences between struct and record struct?
Thanks for the suggestion. Please add it to the list on the suggestion site so others can vote on it as well: suggestions.iamtimcorey.com/
@@IAmTimCorey Alright, I'll do it, thank you :)
For 40:00 , isn't it due to internal properties are designed to not return through public ToString()?
Yes. I think so. ToString() called from another aasembly on that record type should not expose internals.
Yep, it was because it was protecting me from potential problems (amazing how smart that is).
@@IAmTimCorey is there a way to capture all of these after video creation knowledge into the description? I knew someone would have an answer to this but I had to skim past several comments to get an answer.
Nicely done. Thank You!
Thanks for watching!