次の方法で共有


BinaryFormatter 機能リファレンス

BinaryFormatter は、2002 年に .NET Framework の最初のリリースで初めて導入されました。 BinaryFormatter の使用法を置き換える方法を理解するには、BinaryFormatter のしくみを理解することが役立ちます。

BinaryFormatter では、[Serializable] で注釈が付けられている任意の型、または ISerializable インターフェイスを実装する任意の型のインスタンスをシリアル化できます。

メンバー名

最も一般的なシナリオでは、型は [Serializable] で注釈が付けられます。シリアライザーはリフレクションを使用してすべてのフィールドをシリアル化します (パブリックと非パブリックの両方)。ただし、[NonSerialized] で注釈が付けられたフィールドは除きます。 既定では、シリアル化されたメンバー名は型のフィールド名と一致します。 そのせいで、これまでは、[Serializable] 型でプライベート フィールドの名前が変更された場合でも互換性が失われていました。 BinaryFormatter からの移行中は、シリアル化されたフィールド名がどのように処理され、オーバーライドされたかを理解する必要があります。

C# の自動プロパティ

C# 自動的に実装されるプロパティ ({ get; set; }) の場合、 BinaryFormatter はプロパティではなく、C# コンパイラによって生成されたバッキング フィールドをシリアル化します。 これらのシリアル化されたバッキング フィールドの名前は無効な C# 文字を含んでおり、制御できません。 C# 逆コンパイラ (https://sharplab.io/ILSpy など) は、C# の自動プロパティをランタイムに表示する方法を示すことができます。

[Serializable]
internal class PropertySample
{
    public string Name { get; set; }
}

前のクラスは、C# コンパイラによって次のように変換されます。

[Serializable]
internal class PropertySample
{
    private string <Name>k__BackingField;

    public string Name
    {
        get
        {
            return <Name>k__BackingField;
        }
        set
        {
            <Name>k__BackingField = value;
        }
    }
}

この場合、<Name>k__BackingField は、シリアル化されたペイロードで BinaryFormatter が使用するメンバーの名前になりますnameof またはその他の C# 演算子を使用して、この名前を取得することはできません。

ISerializable インターフェイスには GetObjectData メソッドが付属しています。このメソッドにより、ユーザーは AddValue メソッドのいずれかを使用して名前を制御できます。

// Note lack of any special attribute.
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
    info.AddValue("Name", this.Name);
}

このようなカスタマイズが適用されている場合は、逆シリアル化の実行中にも情報を提供する必要があります。 これは、用意されている Get メソッドの 1 つを使用して SerializationInfo からすべての値を読み取るserializationコンストラクターを使用すれば可能です。

private PropertySample(SerializationInfo info, StreamingContext context)
{
    this.Name = info.GetString("Name");
}

Note

ここでは、nameof 演算子を意図的に使用しませんでした。ペイロードは永続化が可能で、後でプロパティの名前を変更できるためです。 したがって、名前が変更された場合でも (LastName プロパティも導入することにしたため、FirstName に変更するなど)、下位互換性を維持するために、serializationでは、どこかで永続化されている可能性のある古い名前を引き続き使用する必要があります。

Serialization バインダー

SerializationBinder を使用してクラスの読み込みを制御し、読み込むクラスを要求することをお勧めします。 これにより、セキュリティの脆弱性が最小限に抑えられます (攻撃者がペイロードを変更して逆シリアル化し、別のものを読み込む場合でも、許可された型のみが読み込まれます)。

この型を使用するには、その型から継承し、BindToType メソッドをオーバーライドする必要があります。

シリアル化が可能な型のリストは限定的なセットであることが理想的です。どの型がインスタンス化される可能性があるかがわかり、セキュリティの脆弱性を軽減するのに役立つためです。