I have a legit reason to consider using WeakReferences (it’s beyond the UnityEngine.Object conundrum which is what usually plagues people and is clearly not supported).
Here’s the scenario (sry about the length, but I couldn’t shorten it without skipping over the important stuff):
I have a concrete object of type Obj that implements IList, and some of its instances might become large. This will become important in a moment.
This type Obj is a reference type but contains only value types (Y et al) and is fully serializable. I don’t need this serialization too much at this point in time, but it’s a neat and simple convenience if a need arises (and it just might).
I also have a collection object of type ObjCollection on the C# side which allocates, stores, tracks, removes etc objects of type Obj in memory. The design of the system was very specific in places, and to cut story short, the manager doesn’t handle duplicate Obj items (like all hashed collections). Their duplication is tracked exclusively by reference because Obj data is entirely mutable, meaning that one instance could pretend to be an exact copy of some other instance in data, but the system doesn’t care, two different instances are simply not equal. And that’s perfect.
The implication of this design decision is that, while the system itself is capable of tracking everything in O(1) time and works as intended, I cannot truly keep copies by reference. And as I said some of the instances might become large.
Now, with this in mind, I want to introduce a layer of relatively simple logic, to relieve the memory of redundancy (especially once it became apparent I will likely have a lot of copies). My solution was to introduce an interface IObj. And now you’re probably like “you can’t serialize interfaces” and that’s ok. The thing is, I don’t EVER need to serialize ObjCollection, just Obj itself, so that’s also fine. Obj implements IObj, ObjCollection handles IObj items, and that’s it.
What’s the point of this interface, you ask. Well, now I can add another concrete type of ObjProxy which also implements IObj. What I get is that from the ObjCollection’s perspective it’s business as usual, but the proxy object actually holds a reference to a concrete Obj instance, while only PRETENDING to be unique.
tl;dr
But here’s the trouble. You remove Obj instance from the system, you render all ObjProxy instances (which referred to it) invalid. That part is normal and desirable, but what’s not desirable is that these objects now hold a strong reference to Obj. So Obj becomes a zombie object, never to be recycled by GC. (And moreover, you don’t actually get rid of the Obj at all, proxies will maintain reference to it as if nothing happened.)
The solution is obviously a WeakReference pattern. Once ObjCollection (and the rest of the “strong” system) loses a grip on something, it’s over. Any proxies holding onto it should simply become unresolvable, at which point I can simply clean them up once they pop up in a query once in a while or whatever.
It’s a pretty neat design (if you ask me) and imo a legit use of WeakReferences, but what happens if I want to support serialization of ObjProxy like I did for Obj?
I def need to use SerializeReference for the reference itself. But then I get this line of code
[SerializeReference] WeakReference<Obj> _ref;
I know Unity all too well, and I anticipate something similar to an over sped circus train taking a sharp turn.
Does anyone have any experience with this particular use-case?
The worst case is, well, I don’t support serialization for proxies, which sounds like redundant anyway (“don’t you already have that data in Obj?”), but of course there is some overhead “wrapper” data that only proxy knows about which is worth the trouble.