Skip to content

Commit

Permalink
Implement Servant.CreateSingletonsAsync.
Browse files Browse the repository at this point in the history
  • Loading branch information
drewnoakes committed Aug 21, 2016
1 parent ed1c315 commit 9ff24c3
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 7 deletions.
23 changes: 23 additions & 0 deletions Servant.Tests/ServantTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,29 @@ public async Task Add_FuncReturningNullInstanceThrows()
Assert.Equal($"Instance for type \"{typeof(Test1)}\" cannot be null.", exception.Message);
}

[Fact]
public async Task CreateSingletonsAsync()
{
var servant = new Servant();

var callCount = 0;
servant.AddSingleton(() =>
{
callCount++;
return new Test1();
});

Assert.Equal(0, callCount);

await servant.CreateSingletonsAsync();

Assert.Equal(1, callCount);

await servant.ServeAsync<Test1>();

Assert.Equal(1, callCount);
}

#region Differing instance/declared types

private interface IBase { }
Expand Down
23 changes: 16 additions & 7 deletions Servant/Servant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
Expand Down Expand Up @@ -61,10 +62,10 @@ public TypeEntry(Type declaredType)

internal sealed class TypeProvider
{
public Lifestyle Lifestyle { get; }
public IReadOnlyList<TypeEntry> Dependencies { get; }

private readonly Func<object[], Task<object>> _factory;
private readonly Lifestyle _lifestyle;
private readonly Type _declaredType;

[CanBeNull] private object _singletonInstance;
Expand All @@ -73,15 +74,15 @@ public TypeProvider(Func<object[], Task<object>> factory, Type declaredType, Lif
{
_factory = factory;
_declaredType = declaredType;
_lifestyle = lifestyle;
Lifestyle = lifestyle;
Dependencies = dependencies;
}

public async Task<object> GetAsync()
{
// TODO make concurrency-safe here to avoid double-allocation of singleton

if (_lifestyle == Lifestyle.Singleton && _singletonInstance != null)
if (Lifestyle == Lifestyle.Singleton && _singletonInstance != null)
return _singletonInstance;

// find arguments
Expand All @@ -103,7 +104,7 @@ public async Task<object> GetAsync()
if (!_declaredType.IsInstanceOfType(instance))
throw new ServantException($"Instance produced for type \"{_declaredType}\" is not an instance of that type.");

if (_lifestyle == Lifestyle.Singleton)
if (Lifestyle == Lifestyle.Singleton)
_singletonInstance = instance;

return instance;
Expand Down Expand Up @@ -179,11 +180,19 @@ private static bool DependsUpon(TypeEntry dependant, Type dependent)
/// <summary>
/// Eagerly initialises all types registered as having <see cref="Lifestyle.Singleton"/> lifestyle.
/// </summary>
/// <remarks>If all singletons are already instantiated, calling this method has no effect.</remarks>
/// <returns></returns>
/// <remarks>
/// Calling this method is optional. If not used, singletons will be initialised lazily, when first requested.
/// <para />
/// If all singletons are already instantiated, calling this method has no effect.
/// </remarks>
/// <returns>A task that completes when singleton initialisation has finished.</returns>
public Task CreateSingletonsAsync()
{
throw new NotImplementedException();
return Task.WhenAll(
from typeEntry in _entryByType.Values
let provider = typeEntry.Provider
where provider?.Lifestyle == Lifestyle.Singleton
select provider.GetAsync());
}

/// <summary>
Expand Down

0 comments on commit 9ff24c3

Please sign in to comment.