【C#】 タプルのモダンなテクニックの紹介

# 概要
下記講演に関する内容のまとめ　＋　コードサンプルの紹介です。
コードサンプルは動画を何度も見て、コードに起こしたものです。
この記事では、講演内容のうち「タプルのみ」を対象とします。

タプルを適用するもの
・コンストラクタ
・演算子オーバーロード
・スワップ


## 講演
Change your habits:Mordern techniques for modern C# (NDC Conferences@2020)
[講演動画](https://www.youtube.com/watch?v=aUbXGs7YTGo&t=597s,"講演動画")
発表はすべて英語

発表者
　Bill Wagner(Effective C#の著者)さん
備考
　動画のコメントにあるサマリ
　　Fun with tuples 7:08   ★当記事の対象
　　Readonly members & structs 13:25
　　Not null by initialization 22:49
　　Patterns and data 34:34
　　Date & time math 46:05　　

## 動作環境
.NET Core 3.0
C# 8.0

## 前提知識
・C#の基本的な文法を理解してること
・タプル型に関する知識があること
　知識がない場合はこちらを参考にしてください。
　[公式ドキュメント](https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/builtin-types/value-tuples)
　[未確認飛行](https://ufcpp.net/study/csharp/datatype/tuples/?p=1)

## タプルのテクニック適用前のコード
~~~C#
    public struct Point
    {
        private double x;
        public double X
        {
            get => x;
            private set => x = value;
        }
        private double y;
        public double Y
        {
            get => y;
            private set => y = value;
        }
        private double? distance;
        public double Distance
        {
            get
            {
                if(!distance.HasValue)
                    distance = Math.Sqrt(x * x + y * y);
                return distance.Value;
            }
        }
        public Point( double x, double y )
        {
            this.x = x;
            this.y = y;
            distance = default;
        }
        public static bool operator ==( Point left, Point right ) =>
            left.X == right.X && left.Y == right.Y;
        public static bool operator !=( Point left, Point right ) =>
            left.X != right.X || left.Y != right.Y;

        public override bool Equals( object? obj )
        {
            if(obj is Point)
            {
                var otherPT = (Point)obj;
                return this == otherPT;
            }
            else
            {
                return true;
            }
        }
        public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode();
        public void SwapCoords()
        {
            var tmp = X;
            X = Y;
            Y = tmp;
        }
    }
~~~
## タプルのテクニックを適用する
### 1.コンストラクタにタプルを使う
#### 変更前
~~~C#
        public Point( double x, double y )
        {
            this.x = x;
            this.y = y;
            distance = default;
        }
~~~
#### 変更後

~~~C#
        public Point( double x, double y ) =>
            (this.x, this.y, distance) = (x, y, default);
~~~

### 2.演算子オーバーロードにタプルを使う
#### 変更前

~~~C#
        public static bool operator ==( Point left, Point right ) =>
            left.X == right.X && left.Y == right.Y;
        public static bool operator !=( Point left, Point right ) =>
            left.X != right.X || left.Y != right.Y;
~~~

#### 変更後
~~~C#
        public static bool operator ==( Point left, Point right ) =>
            (left.X, left.Y) == (right.X, right.Y);
        public static bool operator !=( Point left, Point right ) =>
            (left.X, left.Y) != (right.X, right.Y);
~~~

### 3.スワップにタプルを使う
#### 変更前

~~~C#
        public void SwapCoords()
        {
            var tmp = X;
            X = Y;
            Y = tmp;
        }
~~~
#### 変更後

~~~C#
public void SwapCoords() => (X, Y) = (Y, X);
~~~