Por que o atributo 'não serializado' não pode ser usado no nível da aula? Como impedir a serialização de uma classe?
-
20-09-2019 - |
Pergunta
Eu tenho um objeto de dados que é clonado profundamente usando uma serialização binária. Esse objeto de dados suporta eventos alterados da propriedade, por exemplo, PriceChanged.
Digamos que eu anexei um manipulador à PriceChanged. Quando o código tenta serializar em serializar o PriceChanged, ele gera uma exceção de que o manipulador não é marcado como serializável.
Minhas alternativas:
- Não posso remover facilmente todos os manipuladores do evento antes da serialização
- Não quero marcar o manipulador como serializável, porque teria que marcar recursivamente todas as dependências dos manipuladores também.
- Eu não quero marcar o PriceChanged como não serralizado - há dezenas de eventos como esse que podem ter manipuladores. EDIT: Outra razão pela qual não posso fazer isso é porque as classes de dados (e, portanto, os eventos) são gerados e não tenho controle direto sobre o código de geração. Idealmente, o código de geração apenas marcaria todos os eventos como não serralizados.
- Idealmente, eu gostaria .NET para parar de descer o gráfico de objetos naquele momento e fazer disso uma 'folha'. Então, por que o .NET não permite que uma classe inteira seja marcada como não serrializada?
--
Finalmente trabalhei nesse problema, tornando o manipulador implementar iserializável e não fazendo nada no método Serialize Constructor/ GetDataObject. Mas, o manipulador ainda está serializado, apenas com todas as suas dependências definidas como NULL - então eu também tive que explicar isso.
Existe uma maneira melhor de impedir a serialização de uma classe inteira? Ou seja, aquele que não requer contabilidade para as dependências nulas?
Solução
Enquanto eu tendem a discordar da abordagem (eu simplesmente marcaria os eventos como não serralizados, independentemente de quantos existam) você provavelmente poderia fazer isso usando substitutos de serialização.
A idéia é que você crie um objeto que implemente o iserializaçõesurrogate e basicamente faça o que você já está fazendo - nada nos métodos GetObjectData e setObjectData. A diferença é que você estaria personalizando a serialização do delegado, não a classe que o contém.
Algo como:
class DelegateSerializationSurrogate : ISerializationSurrogate {
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) {
// do nothing
}
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context) {
// do nothing
return null;
}
}
Em seguida, você registra isso no formatador usando os procedimentos descrito nesta coluna MSDN. Então, sempre que o formatador encontrar um delegado, ele usa o substituto em vez de serializar diretamente o delegado.
Outras dicas
... Existem dezenas de eventos ...
Pessoalmente, então eu acrescentaria os marcadores não serrializados, que para eventos semelhantes a campo são mais facilmente feitos via:
[field: NonSerialized]
public event SomeEventType SomeEventName;
(você não precisa adicionar um delegado de apoio manual)
Quais são os seus requisitos de serialização exatamente? BinaryFormatter
é de muitas maneiras o menos amigável dos serializadores; As implicações nos eventos são um pouco feias e são muito quebradiças se armazenadas (IMO é realmente adequada para transporte, não para armazenamento).
No entanto; Existem muitas alternativas boas que apoiariam cenários mais comuns de "clone profundo":
XmlSerializer
(mas limitado a membros públicos)DataContractSerializer
/NetDataContractSerializer
- Protobuf-net (que inclui
Serializer.DeepClone
para esse fim)
(Observe que na maioria desses suporte de serialização exigiria atributos extras; portanto, não muito diferente de adicionar o [NonSerialized]
atributos em primeiro lugar!)