Modern C#

Nyheter i C# 7

2019-03-04   Dan Wolff

Agenda

  • Numeriska värden
  • Mönstermatchning med is och switch
  • Deklarera utvariabler
  • Värdetuplar med ValueTuple
  • Lokala funktioner
  • default-uttryck
  • throw-uttryck

Numeriska värden

// Före
public const int millionOld = 1000000;
public const int hexOld = 0x00066DD7F389;

// Efter
public const int millionNew = 1_000_000;
public const int hexNew = 0x0006_6DD7_F389;

Mönstermatchning

  • Eng. "pattern matching"
  • Från funktionella programmeringsspråk
  • Alternativ till arv

is och cast

public static double ComputeArea(object shape)
{
    if (shape is Rectangle)
    {
        var r = (Rectangle)shape;
        return r.Length * r.Height;
    }
    else if (shape is Circle)
    {
        var c = (Circle)shape;
        return c.Radius * c.Radius * Math.PI;
    }

    throw new ArgumentException("Unknown shape");
}

is för nya variabler

public static double ComputeArea2(object shape)
{
    if (shape is Rectangle r)
        return r.Length * r.Height;
    else if (shape is Circle c)
        return c.Radius * c.Radius * Math.PI;

    throw new ArgumentException("Unknown shape");
}

switch med typer

public static double ComputeArea3(object shape)
{
    switch (shape)
    {
        case Rectangle r:
            return r.Length * r.Height;
        case Circle c:
            return c.Radius * c.Radius * Math.PI;
        default:
            throw new ArgumentException("Unknown shape");
    }
}

switch och when

public static double ComputeArea4(object shape)
{
    switch (shape)
    {
        case Rectangle r when r.Length == 0 || r.Height == 0:
        case Circle c when c.Radius == 0:
            return 0;
        case Rectangle r:
            return r.Length * r.Height;
        case Circle c:
            return c.Radius * c.Radius * Math.PI;
        default:
            throw new ArgumentException("Unknown shape");
    }
}

Deklarera utvariabler

public string Translate(string key)
{
    string translation;
    if (myDict.TryGetValue(key, out translation))
    {
        return translation;
    }
    else
    {
        // Om vi inte hittade någon översättning,
        // returnera värdet vi fick in.
        return key;
    }
}

Deklarera utvariabler

public string Translate(string key)
{
    if (myDict.TryGetValue(key, out var translation))
    {
        return translation;
    }
    else
    {
        // Om vi inte hittade någon översättning,
        // returnera värdet vi fick in.
        return key;
    }
}

Värdetuplar

  • Likt Tuple, men smidigare
  • Inbyggt i språket, men...
    • Nuget-paket: System.ValueTuple
  • Enklare än anonymt objekt
  • Särskilt bra för privata metoder

Värdetuplar

var letters = ("a", "b");

(string Alpha, string Beta) letters = ("a", "b");

var letters = (Alpha: "a", Beta: "b");

// Varning
(string First, string Second) letters = (Alpha: "a", Beta: "b");

Värdetuplar

private static (int Min, int Max) Range(IEnumerable<int> numbers)
{
    var min = int.MaxValue;
    var max = int.MinValue;
    foreach (var n in numbers)
    {
        min = (n < min) ? n : min;
        max = (n > max) ? n : max;
    }
    return (min, max);
}

Värdetuplar: dekonstruktion

// Här kan man använda `range.Min` och `range.Max`.
var range = Range(numbers);

(int min, int max) = Range(numbers);

var (min, max) = Range(numbers);

Lokala funktioner

Fördelar gentemot privata metoder:

  • Tydligare att scope är begränsat
  • Kan fånga (eng. capture) variabler

Lokala funktioner

Fördelar gentemot lambdauttryck:

  • Bättre kompilatorstöd
  • Har stöd för yield return

Lokala funktioner

public static int Factorial(int n)
{
    if (n < 0)
        throw new ArgumentOutOfRangeException(
            "n must be non-negative");

    return nthFactorial(n);

    int nthFactorial(int number)
    {
        return (number < 2)
            ? 1
            : number * nthFactorial(number - 1);
    }
}

Förenklat default-uttryck

// Före
Func<string, bool> whereCondition = default(Func<string, bool>);
// Efter
Func<string, bool> whereCondition = default;

Förenklat default-uttryck

public class LabeledPoint
{
    public double X { get; }
    public double Y { get; }
    public string Label { get; }

    public LabeledPoint(
        double x,
        double y,
        string label = default)
    {
        X = x;
        Y = y;
        Label = label;
    }
}

throw-uttryck

private string name;
public string Name
{
    get => name;
    set
    {
        if (value == null)
        {
            throw new ArgumentNullException(
                "New name must not be null");
        }

        name = value;
    }
}

throw-uttryck

private string name;
public string Name
{
    get => name;
    set => name = value ??
        throw new ArgumentNullException(
            "New name must not be null");
}

Frågor?

Sammanfattning