C # 9.0 offers concise and immutable types



[ad_1]

For all .NET developers who are still working with the classic .NET Framework 4.8 (or even older versions), sadly there is a sad message ahead: C # 9.0 can no longer be used there. C # 9.0 only runs on .NET 5.0 and .NET Core 3.0 / 3.1, as well as on Xamarin.

The absolute highlight in C # are records, with which you can concisely define classes with value semantics. The following line of code that looks like a constructor preceded by a keyword record, declares a class Person with three properties ID, Vorname, Name is Status (The latter with default value):

public record Person(int ID, string Vorname, string Name, string Status = "unbekannt");

This record class can now be instantiated as a normal class:

Person hs = new Person(123, "Holger", "Schwichtenberg");

and use the data contained therein through the automatically generated properties:

Console.WriteLine($"Person #{hs.ID}: {hs.Vorname} {hs.Name}");

You’ll immediately notice a difference with a normal class if you try to change the value of a property. This assignment after the instance

hs.Vorname = "Dr. Holger";

the compiler no longer allows it and recognizes it with the error

"Error CS8852 Init - only property or indexer 'Person.Vorname' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor".

Instances of a record class defined in this way are immutable after being instantiated. The new key word record it’s a lot of syntactic sugar. With a free decompiler like ILSpy you can reveal that more than one A4 page of program code has actually been created (see Listing 1).

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;

public class Person : IEquatable<Person>
{
    protected virtual Type EqualityContract
    {
        [System.Runtime.CompilerServices.NullableContext(1)]
        [CompilerGenerated]
        get
        {
            return typeof(Person);
        }
    }

    public int ID { get; init; }
    public string Vorname { get; init; }
    public string Name { get; init; }
    public string Status  { get; init; }

    public Person(int ID, string Vorname, string Name, string Status = "unbekannt")
    {
        this.ID = ID;
        this.Vorname = Vorname;
        this.Name = Name;
        this.Status = Status;
        base..ctor();
    }

    public override string ToString()
    {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.Append("Person");
        stringBuilder.Append(" { ");
        if (PrintMembers(stringBuilder))
        {
            stringBuilder.Append(" ");
        }
        stringBuilder.Append("}");
        return stringBuilder.ToString();
    }

    protected virtual bool PrintMembers(StringBuilder builder)
    {
        builder.Append("ID");
        builder.Append(" = ");
        builder.Append(ID.ToString());
        builder.Append(", ");
        builder.Append("Vorname");
        builder.Append(" = ");
        builder.Append((object?)Vorname);
…
        return true;
    }

    [System.Runtime.CompilerServices.NullableContext(2)]
    public static bool operator !=(Person? r1, Person? r2)
    {
        return !(r1 == r2);
    }

    [System.Runtime.CompilerServices.NullableContext(2)]
    public static bool operator ==(Person? r1, Person? r2)
    {
        return (object)r1 == r2 || (r1?.Equals(r2) ?? false);
    }

    public override int GetHashCode()
    {
        return (((EqualityComparer<Type>.Default.GetHashCode(EqualityContract) * -1521134295 + EqualityComparer<int>.Default.GetHashCode(ID)) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Vorname)) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Name)) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Status);
    }

    public override bool Equals(object? obj)
    {
        return Equals(obj as Person);
    }

    public virtual bool Equals(Person? other)
    {
        return (object)other != null && EqualityContract == other!.EqualityContract && EqualityComparer<int>.Default.Equals(ID, other!.ID) && EqualityComparer<string>.Default.Equals(Vorname, other!.Vorname) && EqualityComparer<string>.Default.Equals(Name, other!.Name) && EqualityComparer<string>.Default.Equals(Status, other!.Status);
    }

    public virtual Person <Clone>$()
    {
        return new Person(this);
    }

    protected Person(Person original)
    {
        ID = original.ID;
        Vorname = original.Vorname;
        Name = original.Name;
        Status = original.Status;
    }

    public void Deconstruct(out int ID, out string Vorname, out string Name, out string Status)
    {
        ID = this.ID;
        Vorname = this.Vorname;
        Name = this.Name;
        Status = this.Status;
    }
}

Listing 1: Decompilation of the “Person” record type with the ILSpy decompiler



betterCode () presents: .NET 5.0 – The online event on December 3, 2020

This is what attendees can learn from the experts in the .NET scene:

  • From .NET Framework to .NET Core to .NET 5.0: What does this mean for migration and how big is the effort?
  • What’s new in .NET 5.0?
  • New Features: Discover ASP.NET Core 5.0 and Blazor 5.0
  • The most important linguistic innovations in C # 9
  • Mobile development with .NET 5
  • OR-Mapping mit Entity Framework Core 5.0
  • WinUI 3 as an alternative to WPF and UWP
  • Outlook on .NET 6.0

To the home page

.

[ad_2]
Source link