0

I was reading a book says Captive Dependencies is a issue when keeping dependencies referenced beyond their expected lifetime, for example, you inject a transient service (A) into a scoped service (B)'s constructor as its dependency, because B holds a reference of A, which delays the dispose of A.

I can understand this kind of issue. Let's consider another scenario, both A and B are disposable (implements IDisposable interface) and you inject a scoped service (B) into a transient service (A), which doesn't cause Captive Dependencies technically. But when A is first to be disposed by GC(calls Finalizer which calls Dispose in turn), its Dispose method gets call, which in turn calls B's Dispose method (because A has to call its dependencies' Dispose method when itself is being disposed as a design rule), so B's native resource will be freed, but here is the catch, what if B is also injected into another service C that depends on B, then C will not function properly since its dependency B has alread been freed.

So why all the books I see only mentions Captive Dependencies, all books says you can't inject a dependency that has a shorter life but no book says you can't inject a dependency that has a longer life when those types are disposable? Is my understanding wrong that the issue I mention will not actually happen? I am confused

  • 1
    "because A has to call its dependencies' Dispose method when itself is being disposed as a design rule)". No, this is not the design rule. This is only the case when A is responsible of the creation of B, which it not is when B is injected. See: https://stackoverflow.com/questions/30283564/dependency-injection-and-idisposable – Steven Sep 17 '21 at 19:06

1 Answers1

1

Only call dispose if you are the owner of the object (or if at some point the ownership was transferred explicitly). There are plenty of cases where you might be handed a longer-lived dependency (e.g., service) that you use and you are not responsible for disposing it. Presumably that service's lifetime is managed by somebody else that created that service. And this is pretty common.

Say if you let go of that longer lived service and the GC determines that nobody else is holding on to that service, then it will call the finalizer which should call Dispose on that service, thereby cleaning up that object.

If you are interested, ref counting was done manually in COM days, which is now mostly encapsulated inside GC.

slacker
  • 509
  • 2
  • 6
  • you mean A's Dispose method should not call B's Dispose method? but if A uses SafeHandle, surely A should call its SafeHandle member's Dispose method –  Sep 15 '21 at 09:08