Prägnanter Code mit C# 10

Seite 4: Listings

Inhaltsverzeichnis
01: using System.Runtime.CompilerServices;
02: 
03: // File-Scoped Namespaces
04: namespace Heise.Developer;
05: 
06: // Readonly Record Struct auf dem Stack
07: public readonly record struct Autor(int ID, 
08:                                    string Name, 
09:                     string Artikelstatus = "unbekannt")
10: {
11:  public readonly DateOnly ObjektErzeugungsZeitpunkt { get; } 
12:                          = new DateOnly(2006, 6, 1);
13: 
14:  // Methode mit Caller Argument Expression
15:  public void CheckObjektErzeugungsZeitpunkt
16:  (DateOnly yearMin, DateOnly yearMax,
17:   [CallerArgumentExpression("yearMin")] string? 
18:    yearMinExpression = null,
19:  [CallerArgumentExpression("yearMax")] string? 
20:    yearMaxExpression = null)
21:  {
22:   if (ObjektErzeugungsZeitpunkt < yearMax || 
23         ObjektErzeugungsZeitpunkt > yearMax)
24:   {
25:    throw new ArgumentOutOfRangeException(
26:      nameof(ObjektErzeugungsZeitpunkt),
27:      $"{ObjektErzeugungsZeitpunkt} muss zwischen" + 
28:      $"{yearMin} ({yearMinExpression}) und {yearMax}" + 
29:      $"({yearMaxExpression}) liegen!");
30:   }
31:  }
32: } 
01: // Global Using Directives
02: global using System;
03: global using static System.Console;
04: using Heise.Developer;
05: 
06: WriteLine("C# 10 Demo f�r heise Developer");
07: 
08: // Constant interpolated Strings
09: const string Vorname = "Holger";
10: const string Nachname = "Schwichtenberg";
11: const string GanzerName = $"Dr. {Vorname} {Nachname}";
12: 
13: // Readonly Record Struct instanzieren
14: var hs1 = new Autor(123, GanzerName);
15: // unm�glich, weil readonly: hs1.Artikelstatus = "abgegeben";
16: 
17: // Ver�nderten Klon erstellen
18: var hs2 = hs1 with { Artikelstatus = "abgegeben" };
19: WriteLine(hs2);
20: 
21: // Mixed Deconstruction
22: int id;
23: (id, string name, _) = hs2;
24: WriteLine($"Autor #{id}: {name}");
25: 
26: // Extended Property Pattern
27: object o = hs2;
28: if (o is Autor { ObjektErzeugungsZeitpunkt.Year: 2006 })
29: {
30:  WriteLine("Jahr des ersten Blog-Eintrags stimmt!");
31: }
32: 
33: // Aufruf der Methode mit Caller Argument Expression
34: hs2.CheckObjektErzeugungsZeitpunkt(new DateOnly(1996,4,17), 
35:                        DateOnly.FromDateTime(DateTime.Now));
36: // Funktion via Lambda mit Typherleitung deklarieren
37: var status = (Autor a) => "Artikel von " + a.Name + 
38:   " ist im Status " + a.Artikelstatus;
39: // Funnktion verwenden
40: WriteLine(status(hs2)); 

Die Umbrüche wurden zum Teil zugunsten der Lesbarkeit angepasst.

// Heise.Developer.Autor
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using Heise.Developer;

public readonly struct Autor : IEquatable<Autor>
{
��public int ID { get; init; }

��public string Name { get; init; }

��public string Artikelstatus { get; init; }

��public DateOnly ObjektErzeugungsZeitpunkt { get; }

��public Autor(int ID, string Name, 
               string Artikelstatus = "unbekannt")
��{
����this.ID = ID;
����this.Name = Name;
����this.Artikelstatus = Artikelstatus;
����ObjektErzeugungsZeitpunkt = new DateOnly(2006, 6, 1);
��}

��public void CheckObjektErzeugungsZeitpunkt(
    DateOnly yearMin, DateOnly yearMax, 
    [CallerArgumentExpression("yearMin")] string? 
       yearMinExpression = null, 
    [CallerArgumentExpression("yearMax")] string? 
       yearMaxExpression = null)
��{
����if (ObjektErzeugungsZeitpunkt < yearMax || 
        ObjektErzeugungsZeitpunkt > yearMax)
����{
������DefaultInterpolatedStringHandler 
        defaultInterpolatedStringHandler = 
        new DefaultInterpolatedStringHandler(34, 5);
������defaultInterpolatedStringHandler.AppendFormatted(
        ObjektErzeugungsZeitpunkt);
������defaultInterpolatedStringHandler.AppendLiteral(
        " muss zwischen ");
������defaultInterpolatedStringHandler.AppendFormatted(yearMin);
������defaultInterpolatedStringHandler.AppendLiteral(" (");
������defaultInterpolatedStringHandler.AppendFormatted(
        yearMinExpression);
������defaultInterpolatedStringHandler.AppendLiteral(") und ");
������defaultInterpolatedStringHandler.AppendFormatted(yearMax);
������defaultInterpolatedStringHandler.AppendLiteral(" (");
������defaultInterpolatedStringHandler.AppendFormatted(
        yearMaxExpression);
������defaultInterpolatedStringHandler.AppendLiteral(")

      liegen!");
������throw new ArgumentOutOfRangeException(
        "ObjektErzeugungsZeitpunkt", 
        defaultInterpolatedStringHandler.ToStringAndClear());
����}
��}

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

��private bool PrintMembers(StringBuilder builder)
��{
����builder.Append("ID = ");
����builder.Append(ID.ToString());
����builder.Append(", Name = ");
����builder.Append((object?)Name);
����builder.Append(", Artikelstatus = ");
����builder.Append((object?)Artikelstatus);
����builder.Append(", ObjektErzeugungsZeitpunkt = ");
����builder.Append(ObjektErzeugungsZeitpunkt.ToString());
����return true;
��}

��public static bool operator !=(Autor left, Autor right)
��{
����return !(left == right);
��}

��public static bool operator ==(Autor left, Autor right)
��{
����return left.Equals(right);
��}

��public override int GetHashCode()
��{
����return ((
       EqualityComparer<int>.Default.GetHashCode(ID) * 
       -1521134295 + 
       EqualityComparer<string>.Default.GetHashCode(Name)) * 
       -1521134295 + 
       EqualityComparer<string>.Default.GetHashCode(
         Artikelstatus)) * -1521134295 + 
       EqualityComparer<DateOnly>.Default.GetHashCode(
         ObjektErzeugungsZeitpunkt);
��}

��public override bool Equals(object obj)
��{
������return obj is Autor && Equals((Autor)obj);
��}

��public bool Equals(Autor other)
��{
����return EqualityComparer<int>.Default.Equals(ID, 
                                                other.ID) &&
      EqualityComparer<string>.Default.Equals(Name, 
                                              other.Name) && 
      EqualityComparer<string>.Default.Equals(Artikelstatus, 
                                     other.Artikelstatus) && 
      EqualityComparer<DateOnly>.Default.Equals(
        ObjektErzeugungsZeitpunkt, 
        other.ObjektErzeugungsZeitpunkt);
��}

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

(rme)