Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Register(Fun<,>) style api #206

Merged
merged 6 commits into from
May 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions VContainer/Assets/VContainer/Runtime/ContainerBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public interface IContainerBuilder
object ApplicationOrigin { get; set; }

RegistrationBuilder Register(Type type, Lifetime lifetime);
RegistrationBuilder RegisterInstance(object instance);
RegistrationBuilder Register(RegistrationBuilder registrationBuilder);

void RegisterBuildCallback(Action<IObjectResolver> container);

bool Exists(Type type, bool includeInterfaceTypes = false);
Expand Down Expand Up @@ -52,9 +52,6 @@ public class ContainerBuilder : IContainerBuilder
public RegistrationBuilder Register(Type type, Lifetime lifetime)
=> Register(new RegistrationBuilder(type, lifetime));

public RegistrationBuilder RegisterInstance(object instance)
=> Register(new RegistrationBuilder(instance));

public RegistrationBuilder Register(RegistrationBuilder registrationBuilder)
{
registrationBuilders.Add(registrationBuilder);
Expand Down
14 changes: 11 additions & 3 deletions VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,26 @@ public static RegistrationBuilder Register<TInterface1, TInterface2, TInterface3
where TImplement : TInterface1, TInterface2, TInterface3
=> builder.Register<TImplement>(lifetime).As(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3));

public static RegistrationBuilder Register<TInterface>(
this IContainerBuilder builder,
Func<IObjectResolver, TInterface> implementationConfiguration,
Lifetime lifetime)
where TInterface : class
=> builder.Register(new FuncRegistrationBuilder(implementationConfiguration, typeof(TInterface), lifetime));

public static RegistrationBuilder RegisterInstance<TInterface>(
this IContainerBuilder builder,
TInterface instance)
=> builder.RegisterInstance(instance).As(typeof(TInterface));
=> builder.Register(new InstanceRegistrationBuilder(instance)).As(typeof(TInterface));

public static RegistrationBuilder RegisterInstance<TInterface1, TInterface2>(
this IContainerBuilder builder,
object instance)
TInterface1 instance)
=> builder.RegisterInstance(instance).As(typeof(TInterface1), typeof(TInterface2));

public static RegistrationBuilder RegisterInstance<TInterface1, TInterface2, TInterface3>(
this IContainerBuilder builder, object instance)
this IContainerBuilder builder,
TInterface1 instance)
=> builder.RegisterInstance(instance).As(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3));

public static RegistrationBuilder RegisterFactory<T>(
Expand Down
29 changes: 29 additions & 0 deletions VContainer/Assets/VContainer/Runtime/Internal/FuncRegistration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;

namespace VContainer.Internal
{
sealed class FuncRegistration : IRegistration
{
public Type ImplementationType { get; }
public IReadOnlyList<Type> InterfaceTypes { get; }
public Lifetime Lifetime { get; }

readonly Func<IObjectResolver, object> implementationProvider;

public FuncRegistration(
Func<IObjectResolver, object> implementationProvider,
Type implementationType,
Lifetime lifetime,
IReadOnlyList<Type> interfaceTypes)
{
ImplementationType = implementationType;
Lifetime = lifetime;
InterfaceTypes = interfaceTypes;

this.implementationProvider = implementationProvider;
}

public object SpawnInstance(IObjectResolver resolver) => implementationProvider(resolver);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;

namespace VContainer.Internal
{
sealed class FuncRegistrationBuilder : RegistrationBuilder
{
readonly Func<IObjectResolver, object> implementationConfiguration;

public FuncRegistrationBuilder(
Func<IObjectResolver, object> implementationConfiguration,
Type implementationType,
Lifetime lifetime) : base(implementationType, lifetime)
{
this.implementationConfiguration = implementationConfiguration;
}

public override IRegistration Build() => new FuncRegistration(
implementationConfiguration,
ImplementationType,
Lifetime,
InterfaceTypes);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Threading;

namespace VContainer.Internal
{
sealed class InstanceRegistration : IRegistration
{
public Type ImplementationType { get; }
public IReadOnlyList<Type> InterfaceTypes { get; }
public Lifetime Lifetime { get; }

readonly object implementationInstance;
readonly IInjector injector;
readonly IReadOnlyList<IInjectParameter> parameters;

long injected;

public InstanceRegistration(
object implementationInstance,
Type implementationType,
Lifetime lifetime,
IReadOnlyList<Type> interfaceTypes,
IReadOnlyList<IInjectParameter> parameters,
IInjector injector)
{
ImplementationType = implementationType;
Lifetime = lifetime;
InterfaceTypes = interfaceTypes;

this.implementationInstance = implementationInstance;
this.injector = injector;
this.parameters = parameters;
}

public object SpawnInstance(IObjectResolver resolver)
{
if (Interlocked.CompareExchange(ref injected, 1, 0) == 0)
{
injector.Inject(implementationInstance, resolver, parameters);
}
return implementationInstance;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace VContainer.Internal
{
sealed class InstanceRegistrationBuilder : RegistrationBuilder
{
readonly object implementationInstance;

public InstanceRegistrationBuilder(object implementationInstance)
: base(implementationInstance.GetType(), Lifetime.Singleton)
{
this.implementationInstance = implementationInstance;
}

public override IRegistration Build()
{
var injector = InjectorCache.GetOrBuild(ImplementationType);

return new InstanceRegistration(
implementationInstance,
ImplementationType,
Lifetime,
InterfaceTypes,
Parameters,
injector);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 2 additions & 13 deletions VContainer/Assets/VContainer/Runtime/Internal/Registration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,27 @@ sealed class Registration : IRegistration
public Lifetime Lifetime { get; }

readonly IInjector injector;

readonly IReadOnlyList<IInjectParameter> parameters;
readonly object specificInstance;

internal Registration(
Type implementationType,
Lifetime lifetime,
IReadOnlyList<Type> interfaceTypes,
IReadOnlyList<IInjectParameter> parameters,
IInjector injector,
object specificInstance)
IInjector injector)
{
ImplementationType = implementationType;
InterfaceTypes = interfaceTypes;
Lifetime = lifetime;

this.injector = injector;
this.specificInstance = specificInstance;
this.parameters = parameters;
}

public override string ToString() => $"ConcreteType={ImplementationType.Name} ContractTypes={string.Join(", ", InterfaceTypes)} {Lifetime} {injector.GetType().Name}";

public object SpawnInstance(IObjectResolver resolver)
{
if (specificInstance != null)
{
injector.Inject(specificInstance, resolver, parameters);
return specificInstance;
}
return injector.CreateInstance(resolver, parameters);
}
=> injector.CreateInstance(resolver, parameters);
}

sealed class CollectionRegistration : IRegistration, IEnumerable<IRegistration>
Expand Down
14 changes: 2 additions & 12 deletions VContainer/Assets/VContainer/Runtime/RegistrationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,16 @@ public class RegistrationBuilder

internal readonly Type ImplementationType;
internal readonly Lifetime Lifetime;
internal readonly object SpecificInstance;

internal List<Type> InterfaceTypes;
internal List<IInjectParameter> Parameters;

public RegistrationBuilder(Type implementationType, Lifetime lifetime, List<Type> interfaceTypes = null)
public RegistrationBuilder(Type implementationType, Lifetime lifetime)
{
ImplementationType = implementationType;
InterfaceTypes = interfaceTypes;
Lifetime = lifetime;
}

public RegistrationBuilder(object instance)
{
ImplementationType = instance.GetType();
Lifetime = Lifetime.Singleton;
SpecificInstance = instance;
}

public virtual IRegistration Build()
{
var injector = InjectorCache.GetOrBuild(ImplementationType);
Expand All @@ -38,8 +29,7 @@ public virtual IRegistration Build()
Lifetime,
InterfaceTypes,
Parameters,
injector,
SpecificInstance);
injector);
}

public RegistrationBuilder As<TInterface>()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using VContainer.Internal;
Expand All @@ -19,38 +18,32 @@ public sealed class ComponentRegistrationBuilder : RegistrationBuilder
internal ComponentRegistrationBuilder(
Component prefab,
Type implementationType,
Lifetime lifetime,
List<Type> interfaceTypes = null)
: this(false, default, implementationType, lifetime, interfaceTypes)
Lifetime lifetime)
: this(false, default, implementationType, lifetime)
{
this.prefab = prefab;
}

internal ComponentRegistrationBuilder(
string gameObjectName,
Type implementationType,
Lifetime lifetime,
List<Type> interfaceTypes = null)
: this(false, default, implementationType, lifetime, interfaceTypes)
Lifetime lifetime)
: this(false, default, implementationType, lifetime)
{
this.gameObjectName = gameObjectName;
}

internal ComponentRegistrationBuilder(
Scene scene,
Type implementationType,
List<Type> interfaceTypes = null)
: this(true, scene, implementationType, Lifetime.Scoped, interfaceTypes)
internal ComponentRegistrationBuilder(Scene scene, Type implementationType)
: this(true, scene, implementationType, Lifetime.Scoped)
{
}

ComponentRegistrationBuilder(
bool find,
Scene scene,
Type implementationType,
Lifetime lifetime,
List<Type> interfaceTypes = null)
: base(implementationType, lifetime, interfaceTypes)
Lifetime lifetime)
: base(implementationType, lifetime)
{
this.find = find;
this.scene = scene;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@ public sealed class SystemRegistrationBuilder : RegistrationBuilder
readonly string worldName;
Type systemGroupType;

internal SystemRegistrationBuilder(
Type implementationType,
string worldName,
List<Type> interfaceTypes = null)
: base(implementationType, default, interfaceTypes)
internal SystemRegistrationBuilder(Type implementationType, string worldName)
: base(implementationType, default)
{
this.worldName = worldName;
InterfaceTypes = InterfaceTypes ?? new List<Type>();
InterfaceTypes.Add(typeof(ComponentSystemBase));
InterfaceTypes.Add(ImplementationType);
InterfaceTypes = new List<Type>
{
typeof(ComponentSystemBase),
implementationType
};
}

public override IRegistration Build()
Expand Down
Loading