C# 7.0ではこんなコードが書けます。
public class Person
{
public string FirstName { get; }
public string LastName { get; }
public Person(string firstName, string lastName)
=> (FirstName, LastName) = (firstName, lastName);
}
これは、C# 7.0から入った
を使ったコードです。
これを使わないコードだと、こうなります。
public Person {
public string FirstName { get; }
public string LastName { get; }
public Person(string firstName, string lastName)
{
this.FirstName = firstName;
this.LastName = lastName;
}
}
分解と式形式のコンストラクタを使っても、そんなに可読性は変わらないと思うので、お好みで。
ただ、MSの公式ドキュメントに使ったコード例があるので、読めるようにはしておいたほうがいいでしょう。
ちなみに、C# 6.0から入ったゲッターオンリーのプロパティーも使っています。これを使わないとしたらだいたいこんな感じに。
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を生成しているように読めます。
using System;
public class Person
{
public string FirstName { get; }
public string LastName { get; }
public Person(string firstName, string lastName)
=> (FirstName, LastName) = (firstName, lastName);
}
SharpLabを使って、C# => IL => DecompileしたC#のコードは次の通り。
コードのコンストラクタを見ると、ValueTupleが作成されていません。
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から変更が入ったそうです。これについては、こちらのツイートから辿れる会話もぜひ確認してみてください。
ありがとうございました。
余談
レコードが欲しい・・・
参考リンク
- 分解
- 式形式のコンストラクタ
- 読み取り専用プロパティ
- 分解と式形式のコンストラクタの利用コード例 : 「チュートリアル: null 許容参照型と null 非許容参照型を使用して設計意図をもっと明確に示す」
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