برچسب: about

  • 8 things about Records in C# you probably didn’t know | Code4IT

    8 things about Records in C# you probably didn’t know | Code4IT


    C# recently introduced Records, a new way of defining types. In this article, we will see 8 things you probably didn’t know about C# Records

    Table of Contents

    Just a second! 🫷
    If you are here, it means that you are a software developer.
    So, you know that storage, networking, and domain management have a cost .

    If you want to support this blog, please ensure that you have disabled the adblocker for this site.
    I configured Google AdSense to show as few ADS as possible – I don’t want to bother you with lots of ads, but I still need to add some to pay for the resources for my site.

    Thank you for your understanding.
    Davide

    Records are the new data type introduced in 2021 with C# 9 and .NET Core 5.

    public record Person(string Name, int Id);
    

    Records are the third way of defining data types in C#; the other two are class and struct.

    Since they’re a quite new idea in .NET, we should spend some time experimenting with it and trying to understand its possibilities and functionalities.

    In this article, we will see 8 properties of Records that you should know before using it, to get the best out of this new data type.

    1- Records are immutable

    By default, Records are immutable. This means that, once you’ve created one instance, you cannot modify any of its fields:

    var me = new Person("Davide", 1);
    me.Name = "AnotherMe"; // won't compile!
    

    This operation is not legit.

    Even the compiler complains:

    Init-only property or indexer ‘Person.Name’ can only be assigned in an object initializer, or on ’this’ or ‘base’ in an instance constructor or an ‘init’ accessor.

    2- Records implement equality

    The other main property of Records is that they implement equality out-of-the-box.

    [Test]
    public void EquivalentInstances_AreEqual()
    {
        var me = new Person("Davide", 1);
        var anotherMe = new Person("Davide", 1);
    
        Assert.That(anotherMe, Is.EqualTo(me));
        Assert.That(me, Is.Not.SameAs(anotherMe));
    }
    

    As you can see, I’ve created two instances of Person with the same fields. They are considered equal, but they are not the same instance.

    3- Records can be cloned or updated using ‘with’

    Ok, so if we need to update the field of a Record, what can we do?

    We can use the with keyword:

    [Test]
    public void WithProperty_CreatesNewInstance()
    {
        var me = new Person("Davide", 1);
        var anotherMe = me with { Id = 2 };
    
        Assert.That(anotherMe, Is.Not.EqualTo(me));
        Assert.That(me, Is.Not.SameAs(anotherMe));
    }
    

    Take a look at me with { Id = 2 }: that operation creates a clone of me and updates the Id field.

    Of course, you can use with to create a new instance identical to the original one.

    [Test]
    public void With_CreatesNewInstance()
    {
        var me = new Person("Davide", 1);
    
        var anotherMe = me with { };
    
        Assert.That(anotherMe, Is.EqualTo(me));
        Assert.That(me, Is.Not.SameAs(anotherMe));
    }
    

    4- Records can be structs and classes

    Basically, Records act as Classes.

    public record Person(string Name, int Id);
    

    Sometimes that’s not what you want. Since C# 10 you can declare Records as Structs:

    public record struct Point(int X, int Y);
    

    Clearly, everything we’ve seen before is still valid.

    [Test]
    public void EquivalentStructsInstances_AreEqual()
    {
        var a = new Point(2, 1);
        var b = new Point(2, 1);
    
        Assert.That(b, Is.EqualTo(a));
        //Assert.That(a, Is.Not.SameAs(b));// does not compile!
    }
    

    Well, almost everything: you cannot use Is.SameAs() because, since structs are value types, two values will always be distinct values. You’ll get notified about it by the compiler, with an error that says:

    The SameAs constraint always fails on value types as the actual and the expected value cannot be the same reference

    5- Records are actually not immutable

    We’ve seen that you cannot update existing Records. Well, that’s not totally correct.

    That assertion is true in the case of “simple” Records like Person:

    public record Person(string Name, int Id);
    

    But things change when we use another way of defining Records:

    public record Pair
    {
        public Pair(string Key, string Value)
        {
            this.Key = Key;
            this.Value = Value;
        }
    
        public string Key { get; set; }
        public string Value { get; set; }
    }
    

    We can explicitly declare the properties of the Record to make it look more like plain classes.

    Using this approach, we still can use the auto-equality functionality of Records

    [Test]
    public void ComplexRecordsAreEquatable()
    {
        var a = new Pair("Capital", "Roma");
        var b = new Pair("Capital", "Roma");
    
        Assert.That(b, Is.EqualTo(a));
    }
    

    But we can update a single field without creating a brand new instance:

    [Test]
    public void ComplexRecordsAreNotImmutable()
    {
        var b = new Pair("Capital", "Roma");
        b.Value = "Torino";
    
        Assert.That(b.Value, Is.EqualTo("Torino"));
    }
    

    Also, only simple types are immutable, even with the basic Record definition.

    The ComplexPair type is a Record that accepts in the definition a list of strings.

    public record ComplexPair(string Key, string Value, List<string> Metadata);
    

    That list of strings is not immutable: you can add and remove items as you wish:

    [Test]
    public void ComplexRecordsAreNotImmutable2()
    {
        var b = new ComplexPair("Capital", "Roma", new List<string> { "City" });
        b.Metadata.Add("Another Value");
    
        Assert.That(b.Metadata.Count, Is.EqualTo(2));
    }
    

    In the example below, you can see that I added a new item to the Metadata list without creating a new object.

    6- Records can have subtypes

    A neat feature is that we can create a hierarchy of Records in a very simple manner.

    Do you remember the Person definition?

    public record Person(string Name, int Id);
    

    Well, you can define a subtype just as you would do with plain classes:

    public record Employee(string Name, int Id, string Role) : Person(Name, Id);
    

    Of course, all the rules of Boxing and Unboxing are still valid.

    [Test]
    public void Records_CanHaveSubtypes()
    {
        Person meEmp = new Employee("Davide", 1, "Chief");
    
        Assert.That(meEmp, Is.AssignableTo<Employee>());
        Assert.That(meEmp, Is.AssignableTo<Person>());
    }
    

    7- Records can be abstract

    …and yes, we can have Abstract Records!

    public abstract record Box(int Volume, string Material);
    

    This means that we cannot instantiate new Records whose type is marked ad Abstract.

    var box = new Box(2, "Glass"); // cannot create it, it's abstract
    

    On the contrary, we need to create concrete types to instantiate new objects:

    public record PlasticBox(int Volume) : Box(Volume, "Plastic");
    

    Again, all the rules we already know are still valid.

    [Test]
    public void Records_CanBeAbstract()
    {
        var plasticBox = new PlasticBox(2);
    
        Assert.That(plasticBox, Is.AssignableTo<Box>());
        Assert.That(plasticBox, Is.AssignableTo<PlasticBox>());
    }
    

    8- Record can be sealed

    Finally, Records can be marked as Sealed.

    public sealed record Point3D(int X, int Y, int Z);
    

    Marking a Record as Sealed means that we cannot declare subtypes.

    public record ColoredPoint3D(int X, int Y, int Z, string RgbColor) : Point3D(X, Y, X); // Will not compile!
    

    This can be useful when exposing your types to external systems.

    This article first appeared on Code4IT

    Additional resources

    As usual, a few links you might want to read to learn more about Records in C#.

    The first one is a tutorial from the Microsoft website that teaches you the basics of Records:

    🔗 Create record types | Microsoft Docs

    The second one is a splendid article by Gary Woodfine where he explores the internals of C# Records, and more:

    🔗C# Records – The good, bad & ugly | Gary Woodfine.

    Finally, if you’re interested in trivia about C# stuff we use but we rarely explore, here’s an article I wrote a while ago about GUIDs in C# – you’ll find some neat stuff in there!

    🔗5 things you didn’t know about Guid in C# | Code4IT

    Wrapping up

    In this article, we’ve seen 8 things you probably didn’t know about Records in C#.

    Records are quite new in the .NET ecosystem, so we can expect more updates and functionalities.

    Is there anything else we should add? Or maybe something you did not expect?

    Happy coding!

    🐧



    Source link

  • 5 tricks every C# dev should know about LINQPad &vert; Code4IT

    5 tricks every C# dev should know about LINQPad | Code4IT


    LINQPad is one of the tools I use daily. But still, I haven’t used it at its full power. And you?

    Table of Contents

    Just a second! 🫷
    If you are here, it means that you are a software developer.
    So, you know that storage, networking, and domain management have a cost .

    If you want to support this blog, please ensure that you have disabled the adblocker for this site.
    I configured Google AdSense to show as few ADS as possible – I don’t want to bother you with lots of ads, but I still need to add some to pay for the resources for my site.

    Thank you for your understanding.
    Davide

    LINQPad is one of my best friends: I use it daily, and it helps me A LOT when I need to run some throwaway code.

    There are many other tools out there, but I think that LINQPad (well, the full version!) is one of the best tools on the market.

    But still, many C# developers only use just a few of its functionalities! In this article, I will show you my top 5 functionalities you should know.

    Advanced Dump()

    As many of you already know, to print stuff on the console you don’t have to call Console.WriteLine(something), but you can use something.Dump();

    void Main()
    {
        var user = new User(1, "Davide", "DavideB");
        user.Dump();
    }
    

    Basic usage of Dump()

    You can simplify it by avoiding calling the Dump operation in a separate step: Dump can print the content and return it at the same time:

    var user = new User(1, "Davide", "DavideB").Dump();
    

    Dump() can both print and return a value

    For sure, this simple trick makes your code easier to read!

    Ok, what if you have too many Dump calls and you don’t know which operation prints which log? Lucky for us, the Dump method accepts a string as a Title: that text will be displayed in the output panel.

    var user = new User(1, "Davide", "DavideB").Dump("My User content");
    

    You can now see the “My User content” header right above the log of the user:

    Dump() with title

    Dump containers

    We can do a step further and introduce Dump containers.

    Dump Containers are some sort of sink for your logs (we’ve already talked about sinks, do you remember?). Once you’ve instantiated a DumpContainer object, you can perform some operations such as AppendContent to append some content at the end of the logs, ClearContent to clear the content (obviously!), and Dump to display the content of the Container in the Results panel.

    DumpContainer dc = new DumpContainer();
    
    dc.Content = "Hey!";
    dc.AppendContent("There");
    
    dc.Dump();
    

    Note: you don’t need to place the Dump() instruction at the end of the script: you can put it at the beginning and you’ll see the content as soon as it gets added. Otherwise, you will build the internal list of content and display it only at the end.

    So, this is perfectly valid:

    DumpContainer dc = new DumpContainer();
    dc.Dump();
    
    
    dc.Content = "Hey!";
    dc.AppendContent("There");
    

    Simple usage of Dump container

    You can even explicitly set the content of the Container: setting it will replace everything else.

    Here you can see what happens when we override the content:

    Replace log content with DumpContainer

    Why should we even care? 🤔

    My dear friend, it’s easy! Because we can create more Containers to log different things!

    Take this example: we want to loop over a list of items and use one Container to display the item itself, and another Container to list what happens when we perform some operations on each item. Yeeees, I know, it’s hard to understand in this way: let me show you an example!

    DumpContainer dc1 = new DumpContainer();
    DumpContainer dc2 = new DumpContainer();
    
    dc1.Dump();
    dc2.Dump();
    
    var users = new List<User> {
        new User(1, "Davide", "DavideB"),
        new User(2, "Dav", "Davi Alt"),
        new User(3, "Bellone", "Bellone 3"),
    };
    
    foreach (var element in users)
    {
        dc1.AppendContent(element);
        dc2.AppendContent(element.name.ToUpper());
    }
    

    Here we’re using two different containers, each of them lives its own life.

    Using multiple containers

    In this example I used AppendContent, but of course, you can replace the full content of a Container to analyze one item at a time.

    I can hear you: there’s another question in your mind:

    How can we differentiate those containers?

    You can use the Style property of the DumpContainer class to style the output, using CSS-like properties:

    DumpContainer dc2 = new DumpContainer();
    dc2.Style = "color:red; font-weight: bold";
    

    Now all the content stored in the dc2 container will be printed in red:

    Syling DumpContainer with CSS rules

    Great stuff 🤩

    Read text from input

    Incredibly useful, but often overlooked, is the ability to provide inputs to our scripts.

    To do that, you can rely on the Util.ReadLine method already included in LINQPad:

    string myContent = Util.ReadLine();
    

    When running the application, you will see a black box at the bottom of the window that allows you to write (or paste) some text. That text will then be assigned to the myContent variable.

    Using input in LINQPad

    There’s a nice overload that allows you to specify a sort of title to the text box, to let you know which is the current step:

    Input boxes can have a title

    Paste as escaped string

    This is one of my favorite functionalities: many times I have to escape text that contains quotes, copied from somewhere else to assign it to a string variable; I used to lose time escaping those values manually (well, using other tools that still are slower than this one).

    Take this JSON:

    {
      "name": "davide",
      "gender": "male",
      "probability": 0.99,
      "count": 82957
    }
    

    Assigning it manually to a string becomes a mess. Lucky for us, we can copy it, get back on LINQPad, right-click, choose “Paste as escaped string” (or, if you prefer, use Alt+Shift+V) and have it already escaped and ready to be used:

    Escaped string in LINQPad

    That operation will generate this string:

    string content = "{\n\t\"name\": \"davide\",\n\t\"gender\": \"male\",\n\t\"probability\": 0.99,\n\t\"count\": 82957\n}";
    

    Not bad, isn’t it? 😎

    xUnit test support

    Another nice functionality that you can use to toy with classes or methods you don’t know is the xUnit test support.

    By clicking on the Query > Add XUnit Test Support, you can add xUnit to your query and write (and run, obviously) unit tests.

    All those tests are placed in a region named Tests:

    and can be run both by pressing Alt+Shift+T or by calling RunTests() in the Main method.

    After running the tests you will see a report with the list of the tests that passed and the details of the tests that failed:

    xUnit test result

    This article first appeared on Code4IT

    Wrapping up

    We’ve seen 5 amazing tricks to get the best out of LINQPad. In my opinion, every C# developer that uses this tool should know those tricks, they can really boost your productivity.

    Did you already know all of them? Which are your favorites? Drop a message in the comments section or on Twitter 📧

    Happy coding!

    🐧





    Source link