Unity中InjectionConstructor与InjectionFactory懒加载差异及注册时机问询
Great question—let’s break this down clearly, starting with the lazy loading differences between InjectionConstructor and InjectionFactory, then digging into your specific registration code.
Let’s start with the core lazy loading distinction between these two Unity injection features:
InjectionConstructor:
- This is used to explicitly define constructor arguments during type registration. The critical detail here is that any direct values or resolution calls you pass as arguments are evaluated immediately at registration time—there’s no inherent lazy loading. If you pass
Container.ResolveAll<ITYPE>()directly toInjectionConstructor, that resolution happens the moment you callRegisterType, not when you first ask for aSOMETYPEinstance. - To get lazy behavior with
InjectionConstructor, you’d need to wrap dependencies inLazy<T>or pass a factory method as an argument, but that’s not the default behavior.
- This is used to explicitly define constructor arguments during type registration. The critical detail here is that any direct values or resolution calls you pass as arguments are evaluated immediately at registration time—there’s no inherent lazy loading. If you pass
InjectionFactory:
- This is a delegate that runs only when the container first resolves the target type (and again later if your lifetime manager allows multiple instances). This is inherently lazy because the factory logic doesn’t execute until someone actually requests the type.
- Any resolution logic (like
ResolveAll<ITYPE>()) placed inside the factory delegate will run at resolve time, not registration time. This is where you get true lazy loading for your dependencies.
Container.ResolveAll<ITYPE>() in Your Registration Looking at your specific code:
Container.RegisterType<SOMETYPE>(new ContainerControlledLifetimeManager(), new InjectionConstructor(Container.ResolveAll<ITYPE>()));
The Container.ResolveAll<ITYPE>() call executes during registration, not when you first resolve SOMETYPE. Here’s the breakdown:
- In C#, method arguments are evaluated before they’re passed to a constructor. So when you create the
InjectionConstructorinstance,ResolveAll<ITYPE>()runs immediately to generate the argument value. - This means all
ITYPEimplementations are resolved and collected at app startup (when you registerSOMETYPE). If you add newITYPEregistrations after this line, they won’t be included in theSOMETYPEinstance—since the collection was already built during registration.
The timing difference leads to some important practical distinctions:
Dependency freshness:
InjectionConstructorwith directResolveAll: The collection ofITYPEinstances is fixed at registration time. No updates later will affect it.InjectionFactorywithResolveAllinside the delegate: The collection is built whenSOMETYPEis first resolved, so it includes anyITYPEregistrations added after the initialRegisterTypecall.
Startup overhead:
- If
ITYPEimplementations are resource-heavy to instantiate, usingInjectionConstructoradds that overhead to your app’s startup phase (when registration runs). InjectionFactorydelays that overhead until the first timeSOMETYPEis actually used, which can help with faster startup times.
- If
Flexibility:
InjectionFactorylets you add dynamic logic (like conditional resolution) that runs at resolve time, which isn’t possible with a staticInjectionConstructorargument.
For example, if you want lazy loading and dynamic dependency collection, here’s how you’d rewrite your registration with InjectionFactory:
Container.RegisterType<SOMETYPE>(new ContainerControlledLifetimeManager(), new InjectionFactory(container => new SOMETYPE(container.ResolveAll<ITYPE>()) ));
In this case, ResolveAll<ITYPE>() runs only when SOMETYPE is first resolved, so it picks up any late-registered ITYPE implementations.
内容的提问来源于stack exchange,提问作者mike00

