Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O BinaryFormatter foi introduzido pela primeira vez com a versão inicial do .NET Framework em 2002. Para entender como substituir o uso do BinaryFormatter, ajuda a saber como BinaryFormatter funciona.
BinaryFormatter pode serializar qualquer instância de qualquer tipo que seja anotada ou [Serializable] implemente a ISerializable interface.
Member names
No cenário mais comum, o tipo é anotado com [Serializable] e o serializador usa 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 de campos públicos corresponderão aos nomes de campos do tipo. Para campos não públicos definidos em classes herdadas, os nomes dos membros consistem em nome de tipo herdado, um + sinal e o nome do campo ($InheritedClassName+$nonPublicFieldName). A serialização de nomes de campos historicamente leva a incompatibilidades mesmo quando campos privados são renomeados em tipos [Serializable]. Durante as migrações para longe de BinaryFormatter, tornou-se necessário entender como os nomes de campos serializados eram tratados 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 tempo de execução.
[Serializable]
internal class PropertySample
{
public string Name { get; set; }
}
A classe anterior é traduzida 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 GetObjectData método que permite aos usuários controlar os nomes, usando um dos AddValue métodos.
// 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 , onde 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");
}
Note
O nameof operador não foi usado propositalmente aqui, pois a carga útil pode ser persistente e a propriedade pode ser renomeada em um momento posterior. Portanto, mesmo que ele seja renomeado (digamos para FirstName porque decidas também introduzir uma propriedade LastName), para permanecer retrocompatível, a serialização ainda deve usar o nome antigo que pudesse ter sido persistido em algum lugar.
Serialization aglutinante
Recomenda-se usar SerializationBinder para controlar o carregamento de classe e determinar qual classe carregar. Isso minimiza as vulnerabilidades de segurança (para que apenas os tipos permitidos sejam carregados, mesmo que o invasor modifique a carga para desserializar e carregar outra coisa).
Usar esse tipo requer herdar dele e substituir o BindToType método.
Idealmente, 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.