C# 7 New Features

Tokyo .NET Developers meetup #17

@TanakaTakayoshi (@tanaka_733)

WHO AM I 

@TanakaTakayoshi (English) or @tanaka_733 (Japanese)

WORKING FOR...

Also

  • Microsoft MVP 
  • Blogs and Slides

C# 7 is STILL Preview

There would be some change until GA.

Today codes are open in my GitHub repo.

Try it with VS 2017 RC

(VS Code with .NET Core  1.0 Preview 3 on Linux)

10 New Features in C# 7

  • Data Consumption
    1. Out variables
    2. Pattern matching
    3. Tuples
    4. Deconstruction
  • Performance 
    1. Local functions
    2. Ref return and locals
    3. Generalized async return types
  • Code Simplification
    1. Literal improvements
    2. More expression bodied members
    3. Throw expressions
void PrintCoordinates(Point p)
{
    p.GetCoordinates(out var x1, out var y1);
    p.GetCoordinates(out var x, out var _);
    p.GetCoordinates(out var _, out var y);
    WriteLine($"({x}, {y})");
}

void PrintStars(string s)
{
    if (int.TryParse(s, out var i))
        WriteLine(new string('*', i));
    else
        WriteLine("Cloudy - no stars tonight!");
    WriteLine($"input value is : {i}");//can access i
}

Out Variables

switch (shape)
{
    case Circle c:
        WriteLine($"circle with radius {c.Radius}");
        break;
    case Rectangle s when (s.Length == s.Height):
        WriteLine($"{s.Length} x {s.Height} square");
        break;
    case Rectangle r:
        WriteLine($"{r.Length} x {r.Height} rectangle");
        break;
    default:
        WriteLine("<unknown shape>");
        break;
    case null:
        throw new ArgumentNullException(nameof(shape));
}

Pattern Matching

The default label is always evaluated last. 

Other case labels are evaluated from top to bottom.

public void Run()
{
    var names = GetPrice(1);
    WriteLine($"found {names.Item1} {names.Item2}."); 
    WriteLine($"found {names.price} {names.discount}."); 
    (int first, int middle) = GetPrice(4); 
    (int price, int _) = GetPrice(6); 
}

(int price, int discount) GetPrice(int itemId)
{
    var product = (500, 100);
    return product;
}

Tuples

public void Run()
{
    // calls Deconstruct(out myX, out myY);
    (var myX, var myY) = new Point(3, 5); 
    WriteLine($"{myX} {myY}");
    //discard
    (var x1, var _) = new Point(4, -3);
    WriteLine($"{x1}");
}

class Point
{
    public void Deconstruct(out int x, out int y)
    {
        x = X;
        y = Y;
    }
}

DECONSTRUCTION

private BigInteger GetFactorialUsingLocal(int number)
{
    BigInteger result = number;
    while (number > 1)
    {
        Multiply(number - 1);
        number--;
    }
    void Multiply(int x) => result *= x;
    return result;
}

LOCAL functions

public void Run()
{
    int[] array = { 1, 15, -39, 0, 7, 14, -12 };
    ref int place = ref Find(7, array); 
    place = 9; // replaces 7 with 9 in the array
    WriteLine(array[4]); // prints 9
}

public ref int Find(int number, int[] numbers)
{
    for (int i = 0; i < numbers.Length; i++)
    {
        if (numbers[i] == number)
        {
            return ref numbers[i]; 
        }
    }
    throw new IndexOutOfRangeException($"{nameof(number)} not found");
}

Ref returns & locals

async ValueTask<int> SearchAsync(int a)
{
    if (a != 100)
        return 0;
    await Task.Delay(1000);
    return 1;
}

Generaised ASYNC Rerutn Types

This code can't work at present.

int a1 = 50;
int a2 = 0b01011;
int a3 = 0B101011100;

int i1 = 0b1000_0110_1110;
long i2 = 0xdead_beaf;
var i3 = 123_456_789;
var i4 = 1___2__3_____4; //1234

literal improvements

class Person
{
    private static ConcurrentDictionary<int, string> names 
        = new ConcurrentDictionary<int, string>();
    
    private int id = GetId();

    private static int GetId()
    {
        return 1;
    }

    public Person(string name) => names.TryAdd(id, name); // constructors

    ~Person() => names.TryRemove(id, out _);              // destructors

    public string Name
    {
        get => names[id];                                 // getters
        set => names[id] = value;                         // setters
    }
}

Exoression bodied members

class Person2
{
    public string Name { get; }

    public Person2(string name) 
        => Name = name ?? throw new ArgumentNullException(name);

    public string GetFirstName()
    {
        var parts = Name.Split(' ');
        return (parts.Length > 0) ? 
            parts[0] : throw new InvalidOperationException("No name!");
    }

    public string GetLastName() => throw new NotImplementedException();
}

THRow expressions