Skip to content

Commit

Permalink
Adds AddTransient overload that accepts a value
Browse files Browse the repository at this point in the history
  • Loading branch information
gustavopsantos committed Dec 4, 2023
1 parent 906b9df commit 1c97333
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 1 deletion.
46 changes: 46 additions & 0 deletions Assets/Reflex.Tests/TransientValueResolverTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using FluentAssertions;
using NUnit.Framework;
using Reflex.Core;

namespace Reflex.Tests
{
public class TransientValueResolverTests
{
[Test]
public void AddTransientFromValue_FirstResolve_ShouldReturnValue()
{
var container = new ContainerDescriptor("")
.AddTransient(42)
.Build();

container.Resolve<int>().Should().Be(42);
}

[Test]
public void AddValueType_AsTransientFromValue_SecondResolve_ShouldThrow()
{
var container = new ContainerDescriptor("")
.AddTransient(42)
.Build();

Action resolve = () => container.Resolve<int>();

resolve.Should().NotThrow();
resolve.Should().Throw<Exception>();
}

[Test]
public void AddReferenceType_AsTransientFromValue_SecondResolve_ShouldThrow()
{
var container = new ContainerDescriptor("")
.AddTransient(string.Empty)
.Build();

Action resolve = () => container.Resolve<string>();

resolve.Should().NotThrow();
resolve.Should().Throw<Exception>();
}
}
}
3 changes: 3 additions & 0 deletions Assets/Reflex.Tests/TransientValueResolverTests.cs.meta

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

5 changes: 4 additions & 1 deletion Assets/Reflex/Core/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ public object Resolve(Type type)
return All(elementType).CastDynamic(elementType);
}

return GetResolvers(type).Last().Resolve(this);
var resolvers = GetResolvers(type);
var lastResolver = resolvers.Last();
var resolved = lastResolver.Resolve(this);
return resolved;
}

public TContract Resolve<TContract>()
Expand Down
30 changes: 30 additions & 0 deletions Assets/Reflex/Core/ContainerDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,26 @@ public Container Build()
OnContainerBuilt?.Invoke(container);
return container;
}

public ContainerDescriptor AddType(Type concrete, Type[] contracts, Lifetime lifetime)
{
switch (lifetime)
{
case Lifetime.Singleton: return Add(concrete, contracts, new SingletonTypeResolver(concrete));
case Lifetime.Transient: return Add(concrete, contracts, new TransientTypeResolver(concrete));
default: throw new ArgumentOutOfRangeException(nameof(lifetime), lifetime, null);
}
}

public ContainerDescriptor AddValue(Type concrete, Type[] contracts, Lifetime lifetime)
{
switch (lifetime)
{
case Lifetime.Singleton: return Add(concrete, contracts, new SingletonTypeResolver(concrete));
case Lifetime.Transient: return Add(concrete, contracts, new TransientTypeResolver(concrete));
default: throw new ArgumentOutOfRangeException(nameof(lifetime), lifetime, null);
}
}

public ContainerDescriptor AddSingleton(Type concrete, params Type[] contracts)
{
Expand Down Expand Up @@ -90,6 +110,16 @@ public ContainerDescriptor AddTransient(Type concrete)
{
return AddTransient(concrete, concrete);
}

public ContainerDescriptor AddTransient(object instance, params Type[] contracts)
{
return Add(instance.GetType(), contracts, new TransientValueResolver(instance));
}

public ContainerDescriptor AddTransient(object instance)
{
return AddTransient(instance, instance.GetType());
}

public ContainerDescriptor AddTransient<T>(Func<Container, T> factory, params Type[] contracts)
{
Expand Down
34 changes: 34 additions & 0 deletions Assets/Reflex/Resolvers/TransientValueResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using Reflex.Core;
using Reflex.Enums;

namespace Reflex.Resolvers
{
internal sealed class TransientValueResolver : Resolver
{
private object _value;

public TransientValueResolver(object value)
{
RegisterCallSite();
_value = value;
Disposables.TryAdd(value);
Concrete = _value.GetType();
Lifetime = Lifetime.Transient;
}

public override object Resolve(Container container)
{
IncrementResolutions();

if (_value == null)
{
throw new Exception("Trying to resolve a second time from a TransientValueResolver");
}

var value = _value;
_value = null;
return value;
}
}
}
3 changes: 3 additions & 0 deletions Assets/Reflex/Resolvers/TransientValueResolver.cs.meta

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

9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,15 @@ If object implements `IDisposable` it will be disposed when its parent Container
Theres no need to pass `IDisposable` as contract to have your object disposed, howerver, if you want to retrieve all `IDisposable` by any API `Single<TContract>`, `Resolve<TContract>` or `All<TContract>` then yes, you have to specify it.
> Note that `IStartable` also works for **Transients** but pay attention that any resolve API will create a new instance
### AddTransient (From Value)
```csharp
ContainerDescriptor::AddTransient(object instance, params Type[] contracts)
```
Adds an object already contructed by the user to the container as a transient.
Its gonna be returned only on first time it gets resolved, second time an exception will be throw.
If object implements `IDisposable` it will be disposed when its parent Container are disposed.
Theres no need to pass `IDisposable` as contract to have your object disposed, howerver, if you want to retrieve all `IDisposable` by any API `Single<TContract>`, `Resolve<TContract>` or `All<TContract>` then yes, you have to specify it.

### AddTransient (From Factory)
```csharp
ContainerDescriptor::AddTransient(Func<Container, T> factory, params Type[] contracts)
Expand Down

0 comments on commit 1c97333

Please sign in to comment.