C# 9からは、レコード修飾子を使ってデータをカプセル化するための組み込み機能を提供する参照型を定義できます。 C# 10は参照型を明確にするためにrecordクラス構文を同義語として使うことを可能にし、同じ機能を使ってrecord structが値型を定義できるようにします。
C#における記録のユースケース(ChatGPTの回答):
C#のレコードタイプは最新バージョンで導入された新機能です。 以下のような多くのシナリオで使用できますが、これらに限定されません。
不変データオブジェクト:レコードタイプは不変であり、一度作成されるとプロパティ値は変更できません。 これにより、転送オブジェクト(DTO)や設定設定などの不変データ構造の表現に理想的です。 値オブジェクト:レコードタイプは、参照の同値ではなく属性値に基づいて等価が判定される値オブジェクトを表現するために使用できます。 これにより、日付範囲や座標ポイントなどの価値対象の比較や保存に理想的です。 パターンマッチング:レコードタイプはパターンマッチングと組み合わせて使用できるため、複雑なデータ構造を扱う際により便利になります。 パターンマッチングを使ってレコードオブジェクトの属性値を確認し抽出し、適切なアクションを実行できるようにします。 不変コレクション:レコードタイプはImmutableList、ImmutableDictionaryなどの不変コレクションタイプと組み合わせて、不変なコレクションオブジェクトを作成できます。 これにより、コレクションの内容が改変されず、コードの信頼性とセキュリティが向上します。 これらはレコードタイプのユースケースの一部に過ぎず、ご自身のニーズやコード構造に応じて使用するかどうかを判断できます。 レコードとクラス、構造体の違い
クラスや構造を宣言しインスタンス化する際に使われる構文は、操作を記録するときと同じです。 クラスのキーワードをレコードに置き換えるか、structの代わりにrecord structを使うといいです。 同様に、レコードクラスも継承関係に対して同じ構文をサポートしています。 レコードとクラスの違いは以下の通りです。
- メインコンストラクタの位置パラメータを使って、不変な性質を持つ型を作成・インスタンス化できます。
- クラスにおける参照の等価または非等号を示すメソッドや演算子(例:Object.Equals(Object)および==)は、レコード内の値の等号または非平等を示します。
- with式を使って、選択した属性に新しい値を持つ不変オブジェクトのコピーを作成できます。
- レコードのToStringメソッドは、オブジェクトの型名およびその共通プロパティの名前と値を表示するフォーマット文字列を作成します。
- レコードは別のレコードから継承することができます。 しかし、レコードはクラスから継承できず、クラスもレコードから継承できません。
- レコード構造と構造体の違いは、コンパイラが等式とToStringを決定するための手法を統合する点にあります。 コンパイラは位置レコード構造のデコンストラクトメソッドを合成します。
コンパイラはレコードクラス内の各メインコンストラクタパラメータに対して、初期化のみの共通プロパティを合成します。 レコード構造体では、コンパイラが公開の読み書きプロパティを統合します。 コンパイラはレコード修飾子を含まないクラス型や構造体型のメインコンストラクタ引数のプロパティを作成しません。
記録
レコードクラス参照タイプ(デフォルト:クラスは省略可能) レコード構造体値タイプ
レコード文法シュガー
記録は実際には構文、シュガー、そして最終的な結果がクラスまたは構造体コードとなります。 次のコードを例に挙げましょう。
最後に、以下のコードにコンパイルされます:
Systemを使い、 System.Collections.Genericを使い、 System.Diagnosticsを使い、 System.Reflectionを使い、 System.Runtime.CompilerServicesを使い、 System.Securityを使い、 System.Security.Permissionsを使い、 System.Textを使い、 Microsoft.CodeAnalysisを使い、
[アセンブリ:CompilationRelaxations(8) [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue | DebuggableAttribute.DebuggingModes.DisableOptimizations)) [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [モジュール:検証不可コード] [モジュール:System.Runtime.CompilerServices.RefSafetyRules(11)]
[System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public class PersonInfo : IEquatable<PersonInfo>
{ [コンパイラ生成] [DebuggerBrowsable(DebuggerBrowsableState.Never)] プライベート読み取り文字列<FirstName>k__BackingField;
[コンパイラ生成] [DebuggerBrowsable(DebuggerBrowsableState.Never)] プライベート読み取り文字列<LastName>k__BackingField;
[コンパイラ生成] 保護された仮想型EqualityContract(保護された仮想型EqualityContract) { [コンパイラ生成] 取得 { return: typeof(PersonInfo); } }
公開文字列 FirstName { [コンパイラ生成] 取得 { <FirstName>k__BackingField返す; } [コンパイラ生成] イニット { <FirstName>k__BackingField = 価値; } }
パブリック文字列 LastName { [コンパイラ生成] 取得 { <LastName>k__BackingField返事; } [コンパイラ生成] イニット { <LastName>k__BackingField = 価値; } }
public PersonInfo(文字列 FirstName, string LastName) { <FirstName>k__BackingField = ファーストネーム; <LastName>k__BackingField = 姓; 基。。 ctor(); }
[コンパイラ生成] パブリックオーバーライド文字列 ToString() { StringBuilder stringBuilder = 新しいStringBuilder(); stringBuilder.Append("PersonInfo"); stringBuilder.Append(" { "); もし(PrintMembers(stringBuilder)) { stringBuilder.Append(' '); } stringBuilder.Append('}'); return stringBuilder.ToString(); }
[コンパイラ生成] 保護された仮想ブール PrintMembers(StringBuilder ビルダー) { RuntimeHelpers.EnsureSufficientExecutionStack(); ビルダ。 付録("FirstName = "); ビルダ。 Append((object)FirstName); ビルダ。 Append(", LastName = "); ビルダ。 Append((object)LastName); 真を返す; }
[System.Runtime.CompilerServices.NullableContext(2)] [コンパイラ生成] public static bool operator !=(PersonInfo left , PersonInfo right ) { 帰る! (左=右); }
[System.Runtime.CompilerServices.NullableContext(2)] [コンパイラ生成] public static bool operator ==(PersonInfo 左、PersonInfo 右) { return (object)left == right || ((object)left != null & left。 等しい(右)); }
[コンパイラ生成] パブリックオーバーライド int GetHashCode() { 返却(EqualityComparer<Type>. Default.GetHashCode(EqualityContract) * -1521134295 + EqualityComparer<string>. Default.GetHashCode(<FirstName>k__BackingField)) * -1521134295 + EqualityComparer<string>。 Default.GetHashCode(<LastName>k__BackingField); }
[System.Runtime.CompilerServices.NullableContext(2)] [コンパイラ生成] パブリックオーバーライド Bool Equals(オブジェクト obj) { Equals(PersonInfoとして表示); }
[System.Runtime.CompilerServices.NullableContext(2)] [コンパイラ生成] public virtual bool Equals(PersonInfo other) { return (object)this == other || ((object)other != null && EqualityContract == その他。 EqualityContractおよびEqualityComparer<string>。 Default.Equals(<FirstName>k__BackingField、その他。<FirstName>k__BackingField) および & EqualityComparer<string>。 Default.Equals(<LastName>k__BackingField、その他。<LastName>k__BackingField)); }
[コンパイラ生成] public virtual PersonInfo <Clone>$() { 新しいPersonInfo(this)を戻す; }
[コンパイラ生成] 保護されたPersonInfo(PersonInfoのオリジナル) { <FirstName>k__BackingField = オリジナル。 <FirstName>k__BackingField; <LastName>k__BackingField = オリジナル。 <LastName>k__BackingField; }
[コンパイラ生成] パブリックヴォイド Deconstruct(文字列 ファーストネーム、文字列 ストネーム) { FirstName = これ。 ファーストネーム; 姓=これ。 姓; }
}
名前空間Microsoft.CodeAnalysis
{ [コンパイラ生成] [埋め込み] 内部密封クラス EmbeddedAttribute : Attribute { }
}
名前空間 System.Runtime.CompilerServices
{ [コンパイラ生成] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false) 内部密封クラス NullableAttribute : Attribute { 公開読み取りバイト[] NullableFlags;
public NullableAttribute(byte P_0) { byte[] array = 新しいバイト[1]; array[0] = P_0; NullableFlags = array; }
public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } }
[コンパイラ生成] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate、AllowMultiple = false、Inherited = false) 内部封印クラス NullableContextAttribute : Attribute { パブリック読み取り専用バイトフラッグ;
public NullableContextAttribute(byte P_0) { 旗 = P_0; } }
[コンパイラ生成] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] 内部封印クラス RefSafetyRules属性 : 属性 { 公開読み取り専用 int バージョン;
public RefSafetyRulesAttribute(int P_0) { バージョン=P_0; } }
} 自動的にコンストラクタを生成し、ToString、GetHashCode、Equalsメソッドを書き換え、一部のメソッドも自動生成します。
p1とp2は実際には別物ですが、コンパイラが自動的に比較器(IEquatable)を生成し、EqualsメソッドとGetHashCodeメソッドを書き換えたため、出力は真でした。 ToStringメソッドを呼び出すのも、記録された値を出力するのに非常に直感的です。 以下に示すように:
記録
必須:required修飾子は、適用されるフィールドや属性がすべてのコンストラクタまたはオブジェクト初期化器によって初期化されなければならないことを示します。 そのタイプの新しいインスタンスを初期化するために使われる表現は、必要なすべてのメンバーを初期化しなければなりません。 参考:ハイパーリンクのログインが見えます。
イニット: C# 9以降では、initキーワードはプロパティやインデクサ内のアクセサメソッドを定義します。 init専用ライブラリはオブジェクト構築時に属性やインデクサ要素にのみ値を割り当てます。 これにより不変性が強制され、一度オブジェクトが初期化されると変更できなくなります。 参考:ハイパーリンクのログインが見えます。
で: いくつかの修正を加えてインスタンスを再現する必要がある場合は、with式を使って非破壊的な変更を実装できます。 式を用いて、既存のレコードインスタンスのコピーである新しいレコードインスタンスを作成し、指定されたプロパティやフィールドを修正します。 参考:ハイパーリンクのログインが見えます。
したがって、レコードは次のように定義できます。
必須、init、そして実際には構文のシュガーが使われているなら、自動生成の$メソッドを呼び出します<Clone>そして属性の値を修正します。 次のように:
コード:
レコード属性
時には、JSONのシリアル化機能や記述情報などの機能を追加する必要があることもあります。
リソース:
ハイパーリンクのログインが見えます。
ハイパーリンクのログインが見えます。
|