More improvements for ResolveImp

Developer
Feb 27, 2009 at 12:39 AM
InitializeInstace is alway called after CreateInstance so merge with a little check for Reuse.None.
Change GetEntry to a loop instead of recursive.
code below:

 

private TService ResolveImpl<TService, TFunc>(string name, Func<TFunc, TService> invoker, bool throwIfMissing)

 

{

 

var key = new ServiceKey(typeof(TService), typeof(TFunc), name);

 

 


var
entry = GetEntry<TService>(key);

 

 

if (entry != null)

 

{

 

switch (entry.Reuse)

 

{

 

case ReuseScope.Hierarchy:

 

 

break;

 

 

case ReuseScope.Container:

 

 

if (entry.Container != this)

 

{

 

// If the container for the registration entry is

 

 

// not the same as the current container, clone

 

 

// the entry and register locally on this container

 

 

// for further resolutions.

 

services[key] = entry = entry.CloneFor(

this);

 

}

 

break;

 

 

case ReuseScope.None:

 

 

break;

 

 

default:

 

 

throw new ResolutionException(Properties.Resources.ResolutionException_UnknownScope);

 

}

 

 

if (entry.Instance == null)

 

{

 

return CreateAndInitializeInstance<TService, TFunc>(entry, invoker);

 

}

 

return (TService)entry.Instance;

 

}

 

// entry is not found

 

 

if (throwIfMissing)

 

 

return ThrowMissing<TService>(name);

 

 

else

 

 

return default(TService);

 

}

 

private static TService CreateAndInitializeInstance<TService, TFunc>(ServiceEntry<TService> entry, Func<TFunc, TService> invoker)

 

{

 

var factory = (TFunc)entry.Factory;

 

 

var instance = invoker(factory);

 

 

// Save instance if Hierarchy or Container Reuse

 

 

if (entry.Reuse != ReuseScope.None)

 

entry.Instance = instance;

 

// Track for disposal if necessary

 

 

if (entry.Owner == Owner.Container && instance is IDisposable)

 

entry.Container.disposables.Push(

new WeakReference(instance));

 

 

// Call initializer if necessary

 

 

if (entry.Initializer != null)

 

entry.Initializer(entry.Container, instance);

 

return instance;

 

}

 

private ServiceEntry<TService> GetEntry<TService>(ServiceKey key)

 

{

 

ServiceEntry entry = null;

 

 

// Go up the hierarchy always for registrations.

 

 

Container container = this;

 

 

while (!container.services.TryGetValue(key, out entry) && container.parentContainer != null)

 

{

container = container.parentContainer;

}

 

return (ServiceEntry<TService>)entry;

 

}

Coordinator
Feb 27, 2009 at 3:36 AM
Would be SO much better if you could submit a patch!!!

It's hard to do the diff from this (badly) formatted crap made by the comment form :S

Trying to capture changes anyway...

Thanks!!!
Coordinator
Feb 27, 2009 at 3:57 AM
Cool refactorings Dennis!
Will be in for the next refactoring-only screencast.

BTW, the initializer being run with the wrong container needed a new test to showcase the bug, which you fixed in your code ;)