Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O BinaryFormatter foi introduzido pela primeira vez com a versão inicial do .NET Framework em 2002. Para entender como substituir o uso de BinaryFormatter, é útil saber como BinaryFormatter funciona.
BinaryFormatter pode serializar qualquer instância de qualquer tipo que seja anotada com [Serializable] ou implementa a interface ISerializable.
Nomes dos membros
No cenário mais comum, o tipo é anotado com [Serializable] e o serializador usa a reflexão para serializar todos os campos (públicos e não públicos), exceto aqueles que são anotados com [NonSerialized]. Por padrão, os nomes de membros serializados corresponderão aos nomes de campo do tipo. Isso historicamente levou a incompatibilidades quando até mesmo campos privados são renomeados em tipos [Serializable]. Durante as migrações para fora do BinaryFormatter, torna-se necessário entender como os nomes de campo serializados foram manipulados e substituídos.
Propriedades automáticas do C#
Para propriedades implementadas automaticamente em C# ({ get; set; }), BinaryFormatter serializará os campos de suporte gerados pelo compilador C#, não as propriedades. Os nomes desses campos de suporte serializados contêm caracteres C# ilegais e não podem ser controlados. Um descompilador C# (como https://sharplab.io/ ou ILSpy) pode demonstrar como as propriedades automáticas do C# são apresentadas ao runtime.
[Serializable]
internal class PropertySample
{
public string Name { get; set; }
}
A classe anterior é convertida pelo compilador C# para:
[Serializable]
internal class PropertySample
{
private string <Name>k__BackingField;
public string Name
{
get
{
return <Name>k__BackingField;
}
set
{
<Name>k__BackingField = value;
}
}
}
Nesse caso, <Name>k__BackingField é o nome do membro que BinaryFormatter usa na carga serializada. Não é possível usar nameof ou qualquer outro operador C# para obter esse nome.
A ISerializable interface vem com um método GetObjectData que permite aos usuários controlar os nomes, usando um dos métodos AddValue.
// Note lack of any special attribute.
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Name", this.Name);
}
Se essa personalização tiver sido aplicada, as informações também precisarão ser fornecidas durante a desserialização. Isso é possível usando o construtor de serialização , em que todos os valores são lidos de SerializationInfo com um dos métodos Get que ele fornece.
private PropertySample(SerializationInfo info, StreamingContext context)
{
this.Name = info.GetString("Name");
}
Observação
O operador nameof não foi usado propositalmente aqui, pois a carga pode ser mantida e a propriedade pode ser renomeada posteriormente. Portanto, mesmo que seja renomeado (digamos para FirstName porque você decide também introduzir uma propriedade LastName), para permanecer compatível com versões anteriores, a serialização ainda deve usar o nome antigo que poderia ter sido persistido em algum lugar.
Serialization fichário
É recomendável usar SerializationBinder para controlar o carregamento de classe e determinar qual classe carregar. Isso minimiza as vulnerabilidades de segurança (portanto, apenas os tipos permitidos são carregados, mesmo que o invasor modifique a carga para desserializar e carregar outra coisa).
O uso desse tipo requer herdar dele e substituir o método BindToType.
De modo ideal, a lista de tipos serializáveis é fechada porque significa que você sabe quais tipos podem ser instanciados, o que ajudará a reduzir as vulnerabilidades de segurança.