C#の分解と式形式のコンストラクタの組み合わせ

C# 7.0ではこんなコードが書けます。

```csharp
public class Person
{
    public string FirstName { get; }
    public string LastName { get; }

    public Person(string firstName, string lastName)
        => (FirstName, LastName) = (firstName, lastName);
}
```

これは、C# 7.0から入った

* [分解](https://docs.microsoft.com/ja-jp/dotnet/csharp/deconstruct)
* [式形式のコンストラクタ](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members#constructors)

を使ったコードです。

これを使わないコードだと、こうなります。

```csharp
public Person {
    public string FirstName { get; }
    public string LastName { get; }

    public Person(string firstName, string lastName)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
    }
}
```

[分解](https://docs.microsoft.com/ja-jp/dotnet/csharp/deconstruct)と[式形式のコンストラクタ](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members#constructors)を使っても、そんなに可読性は変わらないと思うので、お好みで。

ただ、MSの公式ドキュメントに使った[コード例](https://docs.microsoft.com/ja-jp/dotnet/csharp/tutorials/nullable-reference-types#build-the-survey-with-nullable-and-non-nullable-types)があるので、読めるようにはしておいたほうがいいでしょう。

ちなみに、C# 6.0から入ったゲッターオンリーのプロパティーも使っています。これを使わないとしたらだいたいこんな感じに。

```csharp
public class Person
{
    public string FirstName { get { return firstName; } }
    private readonly string firstName;

    public string LastName { get { return lastName; } }
    private readonly string lastName;

    public PersonOld(string firstName, string lastName)
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
```

# 内部的にValueTupleは作られない

「分解」と「式形式のコンストラクタ」を使ったコードては、一見ValueTupleを生成しているように読めます。

```csharp
using System;

public class Person
{
    public string FirstName { get; }
    public string LastName { get; }

    public Person(string firstName, string lastName)
        => (FirstName, LastName) = (firstName, lastName);
}
```

[SharpLab](https://sharplab.io/)を使って、C# => IL => DecompileしたC#のコードは次の通り。

コードのコンストラクタを見ると、ValueTupleが作成されていません。

```csharp
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
public class Person
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly string <FirstName>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly string <LastName>k__BackingField;

    public string FirstName
    {
        [CompilerGenerated]
        get
        {
            return <FirstName>k__BackingField;
        }
    }

    public string LastName
    {
        [CompilerGenerated]
        get
        {
            return <LastName>k__BackingField;
        }
    }

    public Person(string firstName, string lastName)
    {
        <FirstName>k__BackingField = firstName;
        <LastName>k__BackingField = lastName;
    }
}
```

これはC# 7.1から変更が入ったそうです。これについては、こちらのツイートから辿れる会話もぜひ確認してみてください。

https://twitter.com/RyotaMurohoshi/status/1107489529043148800

* [@xin9le](https://twitter.com/xin9le)さん
* [@neuecc](https://twitter.com/neuecc)さん
* [@ufcpp](https://twitter.com/ufcpp)さん

ありがとうございました。

# 余談

レコードが欲しい・・・

https://github.com/dotnet/roslyn/blob/master/docs/features/records.md


# 参考リンク

* [分解](https://docs.microsoft.com/ja-jp/dotnet/csharp/deconstruct)
* [式形式のコンストラクタ](https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members#constructors)
* [読み取り専用プロパティ](https://docs.microsoft.com/ja-jp/dotnet/csharp/properties#read-only)
* 分解と式形式のコンストラクタの利用コード例 : 「[チュートリアル: null 許容参照型と null 非許容参照型を使用して設計意図をもっと明確に示す](https://docs.microsoft.com/ja-jp/dotnet/csharp/tutorials/nullable-reference-types#build-the-survey-with-nullable-and-non-nullable-types)」


GitHubの関連ありそうなissueやドキュメントはこちら。

* https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-06-28.md#deconstruction-without-valuetuple
* https://github.com/dotnet/roslyn/issues/22382
* https://github.com/dotnet/roslyn/pull/22354/files
* https://github.com/dotnet/roslyn/pull/22731/files
* https://github.com/dotnet/roslyn/pull/20295/files