The Ultimate Guide to C# Records

Sdílet
Vložit
  • čas přidán 14. 06. 2024
  • Become a sponsor to access source code ► / source-code-for-96327491
    Join Discord server with topics on C# ► codinghelmet.com/go/discord
    Enroll course Beginning Object-Oriented Programming with C# ► codinghelmet.com/go/beginning...
    Watch related videos:
    Will All My Classes Look Like Records Now? ► • Will All My Classes Lo...
    Possibility of Discriminated Unions in C# ► • Possibility of Discrim...
    With record types added to C# 9 and 10, we obtained a powerful tool for modeling data in functional models and those that favor DDD. Still, understanding how records work and what hides underneath their deceptively simple syntax is not a trivial task.
    In this video, we first dissect the inner structure of a record and a pair consisting of a base and derived record. We then progress to using some of the less obvious features of records: to model a discriminated union, define custom non-positional properties, or redefine positional properties.
    We then cover the specifics of record structs, finding a niche where they can be valuable, especially in Domain-Driven Design.
    We can utilize their full power only by understanding the inner workings of record types.
    ⌚ 00:00 Intro
    ⌚ 00:40 What's inside a record?
    ⌚ 05:01 Base and derived records
    ⌚ 07:09 Modeling with records
    ⌚ 09:12 record structs
    ⌚ 11:47 Immutable of records
    Thank you so much for watching! Please like, comment & share this video as it helps me a ton!! Don't forget to subscribe to my channel for more amazing videos and make sure to hit the bell icon to never miss any updates.🔥❤️
    ✅🔔 Become a patron ► / zoranhorvat
    ✅🔔 Subscribe ► / @zoran-horvat
    ⭐ Learn more from video courses:
    Beginning Object-oriented Programming with C# ► codinghelmet.com/go/beginning...
    ⭐ Collections and Generics in C# ► codinghelmet.com/go/collectio...
    ⭐ Making Your C# Code More Object-oriented ► codinghelmet.com/go/making-yo...
    ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    ⭐ CONNECT WITH ME 📱👨
    🌐Become a patron ► / zoranhorvat
    🌐Buy me a Coffee ► ko-fi.com/zoranhorvat
    🗳 Pluralsight Courses ► codinghelmet.com/go/pluralsight
    📸 Udemy Courses ► codinghelmet.com/go/udemy
    📸 Join me on Twitter ► / zoranh75
    🌐 Read my Articles ► codinghelmet.com/articles
    📸 Join me on LinkedIn ► / zoran-horvat
    ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    👨 About Me 👨
    Hi, I’m Zoran, I have more than 20 years of experience as a software developer, architect, team lead, and more. I have been programming in C# since its inception in the early 2000s. Since 2017 I have started publishing professional video courses at Pluralsight and Udemy and by this point, there are over 100 hours of the highest-quality videos you can watch on those platforms. On my CZcams channel, you can find shorter video forms focused on clarifying practical issues in coding, design, and architecture of .NET applications.❤️
    ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    ⚡️RIGHT NOTICE:
    The Copyright Laws of the United States recognize a “fair use” of copyrighted content. Section 107 of the U.S. Copyright Act states: “Notwithstanding the provisions of sections 106 and 106A, the fair use of a copyrighted work, including such use by reproduction in copies or phono records or by any other means specified by that section, for purposes such as criticism, comment, news reporting, teaching (including multiple copies for classroom use), scholarship, or research, is not an infringement of copyright." This video and our youtube channel, in general, may contain certain copyrighted works that were not specifically authorized to be used by the copyright holder(s), but which we believe in good faith are protected by federal law and the Fair use doctrine for one or more of the reasons noted above.
    #csharp #dotnet #functionalprogramming
  • Věda a technologie

Komentáře • 85

  • @yufgyug3735
    @yufgyug3735 Před 4 měsíci +24

    'make invalid state unrepresentable' - that is an excellent line

    • @WillEhrendreich
      @WillEhrendreich Před 4 měsíci

      Very idiomatic in fsharp, it's just a very natural way to get things done on that side of dotnet. It's an absolute joy to work with that philosophy.

    • @user-tk2jy8xr8b
      @user-tk2jy8xr8b Před 15 dny

      Unfortunately you still can't have a truly non-nullable reference types nor guarantee struct initialization thanks to every type having `default`

  • @curtmantle7486
    @curtmantle7486 Před 4 měsíci +33

    Devs should watch this even if they think they understand records.

  • @lorenzodepasquale
    @lorenzodepasquale Před 4 měsíci +16

    That NonEmptyString is so elegant

  • @abj136
    @abj136 Před 4 měsíci +3

    To be sure, I 100% understood what you were describing about records in the opening of this video. But I knew approximately 0% of the syntax you showed after, so it’s a good thing I did not skip the rest of this video per your advice.

  • @williamturns1647
    @williamturns1647 Před 4 měsíci +3

    This was a succinct deep-dive into records. Could you kindly make one on pattern matching, too? There are countless ways to use them and it doesn't come naturally to think in pattern-matching style after years of using verbose conditions.

  • @zo1dberg
    @zo1dberg Před měsícem +1

    Great vid and love your accent and storytelling!

  • @Mefator
    @Mefator Před 4 měsíci +5

    You can also simply use *readonly record struct* to make its properties immutable by default.

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +9

      You are right, I should have shown that, too.

  • @TayyabMughalDIK
    @TayyabMughalDIK Před 4 měsíci +4

    This is the best demo on records. It couldn't get better than this one.

  • @nickbarton3191
    @nickbarton3191 Před 4 měsíci +2

    Didn't even think about deriving records, didn't know about equality.
    Glad to dump structs.
    Always learn something from these videos.

  • @matheosmattsson2811
    @matheosmattsson2811 Před 4 měsíci +4

    Love it. Used records a few times but always confused me what they really are tbh. Other than a quick way to create a small class (which is what I saw it as earlier). Now I'm kind of considering migrating a lot of classes to records.. Great video!

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +2

      You have made a valid point. In a domain model of a significant complexity, many types are actually values in their heart. Once you start recognizing those models, you will find many examples where records fit naturally.

  • @averyrealtree545
    @averyrealtree545 Před 3 měsíci +1

    What a wonderful guide! I love your concise and clear communication

  • @Lonchanick
    @Lonchanick Před 4 měsíci +2

    Enough material for at least 10 videos :) Nice!

  • @mr_venik
    @mr_venik Před 4 měsíci +5

    NonEmptyString record struct is nice, but in C# you can still use "default" keyword which would ignore parameterless constructor

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +3

      That is an interesting point about default. Did you check it? I can't find in the documentation whether it invokes the constructor or not.

    • @protox4
      @protox4 Před 4 měsíci +3

      @@zoran-horvat It does not invoke the parameterless constructor. It simply zeroes the struct. It would be hugely breaking otherwise (default is used to clear values to be GC'd everywhere).

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +4

      @@protox4 Yes, you're right. Thank you for this note, I will make sure to remember it the next time I speak about the same matter.

    • @user-tk2jy8xr8b
      @user-tk2jy8xr8b Před 15 dny

      @@protox4 right, it's a straight memzero call. Likely that's the way lang designers answered the question "how do we initialize an array of a non-zero length"

  • @user-ef1ye9nl7r
    @user-ef1ye9nl7r Před 2 měsíci +1

    Excellent, full and deep explanation, thanks a lot 🎉

  • @mahmmoudkinawy2783
    @mahmmoudkinawy2783 Před měsícem +1

    thank you! excellent explanations

  • @DimitrisConstantinou
    @DimitrisConstantinou Před 4 měsíci +3

    I wish i had your deep knowledge of c#

  • @HuneSilver
    @HuneSilver Před 4 měsíci +3

    thanks for the subtitles in english are very useful 🙂

  • @weluvmusicz
    @weluvmusicz Před 4 měsíci +1

    In the record you can define required immutable properties like so: public required string FirstName { get; init; }

  •  Před 4 měsíci +1

    Good stuff. I was looking for the video to discuss with dotnet team in the format: let's meet after a week and discuss it. Your topics so far were in the shelve labeled "this could be too difficult for junios and mids", but this one is flexible. Juniors and seniors will find topics to discuss. Thank you.

  • @kennyhendricks4293
    @kennyhendricks4293 Před 4 měsíci +1

    Damn!!! I love this, I generally use it in DTOs scenario

  • @HOSTRASOKYRA
    @HOSTRASOKYRA Před 4 měsíci +1

    Thank you very much for your explanations!

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci

      Glad if it was useful.

    • @HOSTRASOKYRA
      @HOSTRASOKYRA Před 4 měsíci

      @@zoran-horvat I hope so too, but the path of pure functional programming in C# still scares me.

  • @user-we6wp1ky7f
    @user-we6wp1ky7f Před 4 měsíci +3

    I wondering if records can be used as entity models working with EF

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci

      Not by default, because records are immutable by default and EF tracks entities by reference. Even the terminology uncovers the issue - EF is dealing with entities and records define values.

  • @user-we6wp1ky7f
    @user-we6wp1ky7f Před 4 měsíci +1

    Great video!

  • @ghevisartor6242
    @ghevisartor6242 Před 4 měsíci +1

    i'm dumb, since i'm using Blazor with JsInterop i had some objects that had to be passed between Blazor and javascript, I used a plain class with the IEquatable, when i could have just used record, i even knew about them. Ahh thanks for the video.

  • @Sydra.
    @Sydra. Před 4 měsíci +1

    Too awesome!

  • @kinglygaurav
    @kinglygaurav Před 4 měsíci +1

    Besides learning records, if anyone wants to learn effective communication, watch this!

  • @barionlp
    @barionlp Před 4 měsíci +1

    never heard that i should use record structs over normal structs
    do you have any sources going deeper into that?

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +1

      C# reference is a good starting point: learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record
      You can see from there what exists and then search further for details.

  • @SirBenJamin_
    @SirBenJamin_ Před 4 měsíci

    Do you have any plans to do videos on async/await? I feel like you'd have a lot to say on it ....

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +1

      I do, but I still haven't made any demo code that I would like to talk about. I only have examples I find boring :)
      That is a funny situation, I admit.

  • @alfonsdeda8912
    @alfonsdeda8912 Před 4 měsíci

    Hi Zoran, great video!
    Why class shouldn't derive from another class like in your example with name?

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +1

      Long story :)
      The short version is that the derived class then carries the unwanted baggage of its base, which may cause all kinds of issues later.
      Most frequently, it is better to have a clean abstract base which only provides services that are native to every derived type and nothing more.
      Saving a few lines of code gives little satisfaction when you encounter invalid or dubious assignments later in development.

    • @alfonsdeda8912
      @alfonsdeda8912 Před 4 měsíci +2

      @@zoran-horvatYes, I misunderstood early, I shouldn't inherit functionality that I don't need but rather work with composition.

  • @chrisspire
    @chrisspire Před 3 měsíci

    I would love to use records more but I have one doubt. Even if I just store values that are immutable, I often initialise SOME (but not all) values during creation and update OTHER later. Records don't seem to be in favour in that situation. Or maybe I can do RecordType x = x with {...} to create updated and in fact replace the old object? [I am rather a beginner;)]

    • @zoran-horvat
      @zoran-horvat  Před 3 měsíci

      You are right with your conclusion, but I must ask what is the reason for such practice? I am following the rule that every object must be complete and valid when created. Records are aligned well with that principle.

    • @chrisspire
      @chrisspire Před 3 měsíci

      @@zoran-horvat I use API and there is an class (A) with all starting values when object is created. But these values change over life span of this object. I want to create a record that will store both the initial values of (A) and the values when the object is destoryed. Right now I have a class that copy starting values of (A) when (A) is created and copies values of (A) in the moment the object is destroyed. So half of my object values is filled when (A) is created and half when (A) is destroyed. At the end I serialize those values and perform futher statistical analysis on them.

  • @user-we6wp1ky7f
    @user-we6wp1ky7f Před 4 měsíci

    10:32, record struct could also be defined with readonly keyword.

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci

      Yes, I missed the opportunity to add that, too. That is a viable option when there is no validation.

  • @slowjocrow6451
    @slowjocrow6451 Před 4 měsíci

    It seems most objects I deal with have an Id. Is a record still suitable? It doesn't matter the equality of the other properties, only Id. And what about objects with many properties? Is a record slower?

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +1

      A record is just a class. Therefore, it applies in all situations where you would use a class. It is fine to add the ID to a record. You can even watch my next video where I have used a readonly record struct to define a strongly typed ID itself.

  • @alexhall840
    @alexhall840 Před 4 měsíci

    Can you give some real world examples on using records. I am struggling to think of where I can use them in the business application I am working on.

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci

      Quite a few other videos on my channel are using records in domain modeling.

  • @cbgrasshopper
    @cbgrasshopper Před 4 měsíci

    In a previous video, you recommended against using collections in records due to the issues with deep immutability. Based on this video, it seems you would not have the same concern if the record used frozen collections; is that accurate?

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +1

      Actually, my concern was with equality - collections don't overload Equals and GetHashCode, which are required by the record that might contain them. In that respect, immutable collections and frozen collections are immutable, but still not comparable for equality.

    • @cbgrasshopper
      @cbgrasshopper Před 4 měsíci

      @zoran-horvat In that case, the only option would be a custom type wrapping a collection and implementing the necessary equality members?

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +1

      @@cbgrasshopper The question is what would be the purpose of that. I would rather opt for a common immutable class with no value typed semantics.

  • @MC_DarkMaster
    @MC_DarkMaster Před 4 měsíci

    Can you make a video when to use record structs and when to use record classes?

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +1

      The decision is the same as in the case of class vs. struct.

    • @abj136
      @abj136 Před 4 měsíci

      But I thought the point of classes was pass by reference, which has the point of mutability. Once objects become immutible, the difference seems irrelevant.@@zoran-horvat

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci

      @@abj136 No it's not. Passing by value is an optimization for types that are small enough so that copying every time a value is used does not cost more than allocation, dereferencing, and freeing combined. For types that are as large as a pointer, the value type may take an order of magnitude less CPU cycles when used.

  • @nickw656
    @nickw656 Před 4 měsíci

    The later `record struct` makes the properties mutable by default. Does this seem like a backward trend?

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci

      No, that's just how structs work. You can declare readonly record struct which is immutable by default.

  • @MC_DarkMaster
    @MC_DarkMaster Před 4 měsíci

    Would that be an candidate for record struct? If it does make sense how would a record struct look like?
    public sealed class DateTimeRange
    {
    public DateTime Start { get; private set; }
    public DateTime End { get; private set; }
    public DateTimeRange(DateTime start, DateTime end)
    {
    EnsureStartIsBeforeEnd(Start, End);
    Start = start;
    End = end;
    }
    static void EnsureStartIsBeforeEnd(DateTime start, DateTime end)
    {
    if (start > end)
    {
    throw new DateTimeRangeException("The endtime must not be before the starttime");
    }
    }
    }

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +1

      If you stored DateTime Start and TimeSpan Duration, with DateTime End being a calculated property, then you wouldn't need any validation.

    • @MC_DarkMaster
      @MC_DarkMaster Před 4 měsíci

      @@zoran-horvat That is definetly an good option but would it be possible to to convert it to a record struct? And is an struct the right type for that? I find it very hard to decide when it is better to use an record struct instead of an record class

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci +1

      @@MC_DarkMaster The decision is the same as with any other type. A record struct is a value type, passed by value and copied on every assignment. A record class is a reference type, assigned and passed by reference. Therefore, you will use the form that you need. If you don't know what you need, then a class will be good enough until you find out.

  • @1992jamo
    @1992jamo Před 4 měsíci

    Your syntax is so absolutely alien to me always, but I find your videos very valuable.
    Things like var (firstName1, _) = samuelL; do not even look like C# to me. What is the variable here called?

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci

      That is deconstruction of the record into a tuple, without actually creating a tuple. It stems from an old syntax where you can assign multiple variables in one statement, like (a, b) = (b, a). This will actually swap two values without the use of a third variable.

    • @1992jamo
      @1992jamo Před 4 měsíci +1

      @@zoran-horvat That is extremely interesting, thanks for explaining. I don't think I'll use it, but I appreciate the lesson.

  • @logank.70
    @logank.70 Před 4 měsíci

    Everyone should watch out when using the Primary Constructors feature. There is currently no way to mark the backing fields that it creates as readonly. Not a good feature to use in conjunction with Dependency Injection.

    • @David-id6jw
      @David-id6jw Před 4 měsíci

      You can't make the class parameters readonly, but you can assign them to readonly fields of the same name, and any use in the class will prefer the field over the parameter, making access to the mutable parameter impossible.

    • @obinnaokafor6252
      @obinnaokafor6252 Před 4 měsíci

      the support is coming in C# 13

  • @cloudycloudlet7091
    @cloudycloudlet7091 Před 4 měsíci

    Discord link is not working anymore :(

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci

      I don't know why "never expire, infinite users" Discord links keep expiring every time I share them... That hurts my programmer feelings.
      Try the new link now: discord.com/invite/AgPDChDpxg

  • @halorx9863
    @halorx9863 Před 4 měsíci

    Will you do F# somedays?

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci

      I have no plans for that at this moment.

  • @edkachalov
    @edkachalov Před 4 měsíci

    C# invented record from Pascal

    • @zoran-horvat
      @zoran-horvat  Před 4 měsíci

      Nope. What you are referring to as Pascal record is struct in C#. It was borrowed from C, where it existed even before ANSI C and was borrowed from ALGOL where it existed quite some time before the coming of Pascal. The C# record, on the other hand, is something entirely different and it is borrowed from functional programming languages.
      I hope the matter is clearer now. It is not hard to figure.

  • @zasugod
    @zasugod Před 4 měsíci

    first