Add singleton disposing

This commit is contained in:
Antony Male 2014-09-10 12:59:54 +01:00
parent 3246f5db29
commit 816df04f18
2 changed files with 57 additions and 3 deletions

View File

@ -43,7 +43,7 @@ namespace StyletIoC
public Type Type { get { return this.creator.Type; } }
private readonly object generatorLock = new object();
private Func<IRegistrationContext, object> generator;
protected Func<IRegistrationContext, object> generator;
public RegistrationBase(ICreator creator)
{
@ -82,22 +82,39 @@ namespace StyletIoC
internal class SingletonRegistration : RegistrationBase
{
private Expression instanceExpression;
private object instance;
private readonly IRegistrationContext parentContext;
private bool disposed = false;
public SingletonRegistration(IRegistrationContext parentContext, ICreator creator) : base(creator)
{
this.parentContext = parentContext;
this.parentContext.Disposing += (o, e) =>
{
this.disposed = true;
var disposable = this.instance as IDisposable;
if (disposable != null)
disposable.Dispose();
this.instance = null;
this.instanceExpression = null;
this.generator = null;
};
}
public override Expression GetInstanceExpression(ParameterExpression registrationContext)
{
if (this.disposed)
throw new ObjectDisposedException(String.Format("Singleton registration for type {0}", this.Type.Description()));
if (this.instanceExpression != null)
return this.instanceExpression;
var instance = Expression.Lambda<Func<IRegistrationContext, object>>(this.creator.GetInstanceExpression(registrationContext), registrationContext).Compile()(this.parentContext);
this.instance = Expression.Lambda<Func<IRegistrationContext, object>>(this.creator.GetInstanceExpression(registrationContext), registrationContext).Compile()(this.parentContext);
// This expression yields the actual type of instance, not 'object'
var instanceExpression = Expression.Constant(instance);
var instanceExpression = Expression.Constant(this.instance);
Interlocked.CompareExchange(ref this.instanceExpression, instanceExpression, null);
return this.instanceExpression;
}

View File

@ -35,6 +35,11 @@ namespace StyletUnitTests.StyletIoC
interface IValidator<T> { }
class StringValidator : IValidator<string> { }
class IntValidator : IValidator<int> { }
class C5 : IDisposable
{
public bool Disposed;
public void Dispose() { this.Disposed = true; }
}
[Test]
public void ChildContainerCanAccessRegistrationsOnParent()
@ -191,5 +196,37 @@ namespace StyletUnitTests.StyletIoC
Assert.DoesNotThrow(() => child.Get<IValidator<int>>());
Assert.Throws<StyletIoCRegistrationException>(() => parent.Get<IValidator<int>>());
}
[Test]
public void ContainerDisposesItsSingletonsWhenRequested()
{
var builder = new StyletIoCBuilder();
builder.Bind<C5>().ToSelf().InSingletonScope();
var parent = builder.BuildContainer();
var c5 = parent.Get<C5>();
Assert.False(c5.Disposed);
parent.Dispose();
Assert.True(c5.Disposed);
Assert.Throws<ObjectDisposedException>(() => parent.Get<C5>());
}
[Test]
public void DisposingContainerDoesNotDisposeParentSingletons()
{
var builder = new StyletIoCBuilder();
builder.Bind<C5>().ToSelf().InSingletonScope();
var parent = builder.BuildContainer();
var child = parent.CreateChildBuilder().BuildContainer();
// Make sure it actually gets built
var c5 = parent.Get<C5>();
child.Dispose();
Assert.False(parent.Get<C5>().Disposed);
}
}
}