BinaryFormatter referenční informace o funkcích
Poprvé BinaryFormatter byla představena v počáteční verzi rozhraní .NET Framework v roce 2002. Abyste pochopili, jak nahradit používání BinaryFormatter, pomůže vám zjistit, jak BinaryFormatter funguje.
BinaryFormatter může serializovat libovolnou instanci libovolného typu, který je opatřen poznámkami [Serializable]
nebo implementuje ISerializable rozhraní.
Jména členů
Ve většině běžných scénářů je typ opatřen poznámkami [Serializable]
a serializátor používá reflexi k serializaci všech polí (veřejné i neveřejné) s výjimkou těch, které jsou opatřeny poznámkami [NonSerialized]
. Ve výchozím nastavení budou serializované názvy členů odpovídat názvům polí typu. To v minulosti vedlo k nekompatibilitě, když se u typů přejmenovávají [Serializable]
i soukromá pole. Během migrace mimo BinaryFormatterni je nutné pochopit, jak byly serializované názvy polí zpracovávány a přepsány.
Automatické vlastnosti jazyka C#
V případě jazyka C# automaticky implementovaných vlastností ({ get; set; }
) BinaryFormatter serializuje zálohovaná pole generovaná kompilátorem jazyka C#, nikoli vlastnosti. Názvy těchto serializovaných záložních polí obsahují neplatné znaky jazyka C# a nelze je ovládat. Dekompiler jazyka C# (například https://sharplab.io/ILSpy) může demonstrovat, jak jsou automatické vlastnosti jazyka C# prezentovány modulu runtime.
[Serializable]
internal class PropertySample
{
public string Name { get; set; }
}
Předchozí třída je přeložena kompilátorem jazyka C# na:
[Serializable]
internal class PropertySample
{
private string <Name>k__BackingField;
public string Name
{
get
{
return <Name>k__BackingField;
}
set
{
<Name>k__BackingField = value;
}
}
}
V tomto případě je název člena, <Name>k__BackingField
který BinaryFormatter
používá v serializované datové části. K získání tohoto názvu není možné použít nameof
ani žádný jiný operátor jazyka C#.
Rozhraní ISerializable se dodává s GetObjectData metodou, která uživatelům umožňuje řídit jména pomocí jedné z AddValue metod.
// Note lack of any special attribute.
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Name", this.Name);
}
Pokud je toto přizpůsobení použito, je třeba informace poskytnout také během deserializace. To je možné pomocí konstruktoru serializace , kde jsou všechny hodnoty čteny z SerializationInfo pomocí jedné z metod Get
, které poskytuje.
private PropertySample(SerializationInfo info, StreamingContext context)
{
this.Name = info.GetString("Name");
}
Poznámka:
Operátor nameof
se zde záměrně nepoužil, protože datovou část lze zachovat a vlastnost se může později přejmenovat. Takže i když se přejmenuje (řekněme FirstName
, protože se rozhodnete také zavést LastName
vlastnost), aby zůstala zpětně kompatibilní, serializace by stále měla používat starý název, který by mohl být někde zachován.
Serialization pořadač
Doporučuje se použít SerializationBinder k řízení načítání tříd a určení, jakou třídu se má načíst. Tím se minimalizují ohrožení zabezpečení (takže se načtou jenom povolené typy, i když útočník upraví datovou část tak, aby deserializoval a načetl něco jiného).
Použití tohoto typu vyžaduje dědění z něj a přepsání BindToType metody.
V ideálním případě je seznam serializovatelných typů uzavřen, protože to znamená, že víte, které typy lze vytvořit instance, což pomůže snížit ohrožení zabezpečení.