0

TL;DR;

My custom [Serializable] class overrides GetHashCode and Equals, so multiple distinct objects can be "equal", and it looks like BinaryFormatter calls OnSerialized only once, but calls OnDeserialized twice when two equal but distinct (ReferenceEquals == false) objects exist in the graph.

What can I do to ensure that for every call to [OnSerialized] method [OnDeserialized] method is called exactly once provided I want to keep my GetHashCode and Equals implementations?

Ideally, I would like to instruct BinaryFormatter to use my custom implementation of IEqualityComparer for my custom class so that it would not try to "merge" distinct but equal instances.

Background

The class wraps a refcounted unmanaged handle, that is passed across app domains using BinaryFormatter. To keep the refcount in sync with alive .NET instances, I increase it by 1 in [OnSerialized] handler, assuming the object will be deserialized exactly once, which is violated in the scenario above (the serialized bits are discarded after deserialization).

LOST
  • 2,956
  • 3
  • 25
  • 40
  • I don't think it would make sense for `[OnDeseriaized]` to only be called once. You need the deserialized object to use `GetHashCode` and `Equals.` This seems like an [XY Problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) anyway. Specifially: why are you using `BinaryFormatter` for this? Could you show some code to give a better picture? – ProgrammingLlama Nov 24 '21 at 01:34
  • 1
    Have you looked at the `BinaryFormatter` docs https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter?view=net-6.0, particularly this part: _"Warning BinaryFormatter is insecure and can't be made secure."_ – Flydog57 Nov 24 '21 at 01:36
  • @Flydog57 the security issues of `BinaryFormatter` are irrelevant in my case, because my lib only deserializes what it serialized previously. – LOST Nov 24 '21 at 02:32
  • @Llama I anticipated the XY thing by mentioning my use case in the background section: I need to preserve class instances that wrap unmanaged resources, and have custom implementations of `GetHashCode` and `Equals` across app domains. In particular, for Unity editor. – LOST Nov 24 '21 at 02:35
  • Well, can you provide some code (a [mcve])? – ProgrammingLlama Nov 24 '21 at 02:39
  • @Llama I doubt it will help, but here's a gist: https://gist.github.com/lostmsu/a4268ed09af2e87de9999f8abbbd997e – LOST Nov 24 '21 at 03:13
  • BTW, related question with a very similar problem from 2012 (!) https://stackoverflow.com/a/11462811/231238 – LOST Nov 24 '21 at 03:35

1 Answers1

0

Implementing ISerializable instead of using [OnSerialized] attribute works: GetObjectData gets called for each distinct object even if they are equal by Equals + GetHashCode.

Downsides are:

  1. It is probably slower
  2. Now all types deriving from the wrapper must have a deserializing constructor with signature .ctor(SerializationInfo info, StreamingContext context)
LOST
  • 2,956
  • 3
  • 25
  • 40