Skip to content

Commit

Permalink
0.2 version
Browse files Browse the repository at this point in the history
  • Loading branch information
Niyaz Kashafutdinov committed Mar 7, 2024
1 parent 1f96123 commit bbddd22
Show file tree
Hide file tree
Showing 123 changed files with 1,533 additions and 1,146 deletions.
8 changes: 8 additions & 0 deletions ReDI/.idea/.idea.ReDI.dir/.idea/indexLayout.xml

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

6 changes: 6 additions & 0 deletions ReDI/.idea/.idea.ReDI.dir/.idea/projectSettingsUpdater.xml

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

6 changes: 6 additions & 0 deletions ReDI/.idea/.idea.ReDI.dir/.idea/vcs.xml

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

152 changes: 152 additions & 0 deletions ReDI/.idea/.idea.ReDI.dir/.idea/workspace.xml

Large diffs are not rendered by default.

32 changes: 18 additions & 14 deletions Remouse.DI/BindingConfigurator.cs → ReDI/BindingConfigurator.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
using System;
using System.Collections.Generic;

namespace Remouse.DI
namespace ReDI
{
internal class BindingInfo
{
public bool alwaysNewInstance;
public readonly HashSet<Type> associatedInterfaces = new HashSet<Type>();
public Type boundType;
public object instance;
public bool constructOnBuild;
public bool isDisposable;
public bool AlwaysNewInstance { get; set; }
public HashSet<Type> AssociatedInterfaces { get; } = new HashSet<Type>();
public Type BoundType { get; }
public object? Instance { get; set; }
public bool CreateOnBuild { get; set; }
public bool IsDisposable { get; set; }

public BindingInfo(Type boundType)
{
BoundType = boundType;
}
}

public class BindingConfigurator<T>
Expand All @@ -24,32 +29,31 @@ internal BindingConfigurator(BindingInfo binding)

public BindingConfigurator<T> ImplementingInterfaces()
{
_binding.associatedInterfaces.UnionWith(_binding.boundType.GetInterfaces());
_binding.AssociatedInterfaces.UnionWith(_binding.BoundType.GetInterfaces());
return this;
}

public BindingConfigurator<T> AsDisposable()
{

_binding.isDisposable = true;
_binding.IsDisposable = true;
return this;
}

public BindingConfigurator<T> As<TInterface>()
{
_binding.associatedInterfaces.Add(typeof(TInterface));
_binding.AssociatedInterfaces.Add(typeof(TInterface));
return this;
}

public BindingConfigurator<T> FromInstance(T instance)
{
_binding.instance = instance;
_binding.Instance = instance;
return this;
}

public BindingConfigurator<T> ConstructOnContainerBuild()
public BindingConfigurator<T> CreateOnContainerBuild()
{
_binding.constructOnBuild = true;
_binding.CreateOnBuild = true;
return this;
}
}
Expand Down
161 changes: 161 additions & 0 deletions ReDI/Container.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace ReDI
{
public class Container : IDisposable
{

private readonly List<ServiceRegistration> _registrations = new List<ServiceRegistration>();
private readonly Dictionary<Type, HashSet<ServiceRegistration>> _registrationsByInterface = new Dictionary<Type, HashSet<ServiceRegistration>>();

private bool _isDisposed;
private HashSet<Type> _constructingTypes = new HashSet<Type>();

internal Container(IEnumerable<BindingInfo> bindings)
{
var toBuild = new HashSet<ServiceRegistration>();

foreach (var binding in bindings)
{
var registration = new ServiceRegistration(binding.BoundType, binding.AlwaysNewInstance, binding.IsDisposable, binding.Instance);

foreach (var interfaceType in binding.AssociatedInterfaces)
{
if (!_registrationsByInterface.TryGetValue(interfaceType, out var existingRegistrations))
{
existingRegistrations = new HashSet<ServiceRegistration>();
_registrationsByInterface[interfaceType] = existingRegistrations;
}

existingRegistrations.Add(registration);
}

if (binding.CreateOnBuild)
toBuild.Add(registration);

_registrations.Add(registration);
}

foreach (var buildingService in toBuild)
{
Build(buildingService);
}
}

public void Dispose()
{
if (_isDisposed)
{
#if DEBUG
throw new ObjectDisposedException("Container is already disposed");
#endif
return;
}

foreach (var registration in _registrations)
{
if (registration.IsDisposable && registration.Instance is IDisposable disposable)
disposable.Dispose();
}

_isDisposed = true;
}

public T? Resolve<T>() where T : class
{
var obj = Resolve(typeof(T));
return obj != null ? (T)obj : null;
}

public object? Resolve(Type type)
{
CheckIfDisposed();

if (IsGenericList(type))
{
return ResolveList(type);
}
else
{
return ResolveSingle(type);
}
}

private object? ResolveSingle(Type type)
{
if (!_registrationsByInterface.TryGetValue(type, out var registrations))
{
return null;
}

return Build(registrations.First());
}

private object? ResolveList(Type type)
{
var serviceType = GetListTypeArgument(type);

if (!_registrationsByInterface.TryGetValue(serviceType, out var registrations))
{
return null;
}

var listType = typeof(List<>);
var constructedListType = listType.MakeGenericType(serviceType);

var instance = Activator.CreateInstance(constructedListType, registrations.Count) as IList;
foreach (var registration in registrations)
{
instance.Add(Build(registration));
}

return instance;
}

private bool IsGenericList(Type type)
{
return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(List<>));
}

private Type GetListTypeArgument(Type type)
{
return type.GetGenericArguments()[0];
}

private void CheckIfDisposed()
{
#if DEBUG
if (_isDisposed)
throw new ObjectDisposedException("Container is disposed");
#endif
}

private object Build(ServiceRegistration registration)
{
if (registration.AlwaysNewInstance || registration.Instance == null)
{
CheckForCircularDependency(registration);
registration.Instance = registration.Create(this);
_constructingTypes.Remove(registration.ServiceType);
}

if (!registration.IsInjected)
{
registration.Inject(registration.Instance, this);
}

return registration.Instance;
}

private void CheckForCircularDependency(ServiceRegistration registration)
{
if (!_constructingTypes.Add(registration.ServiceType))
{
throw new CircularDependencyFoundException(registration.ServiceType);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Remouse.DI
namespace ReDI
{
public class ContainerBuilder
{
Expand Down
13 changes: 13 additions & 0 deletions ReDI/Exceptions/CircularDependencyFoundException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace ReDI
{
public class CircularDependencyFoundException : Exception
{
private readonly Type _type;

public CircularDependencyFoundException(Type type) { _type = type; }

public override string Message { get => $"{_type} refers to circular dependency"; }
}
}
18 changes: 18 additions & 0 deletions ReDI/Exceptions/InjectingServiceNotRegisteredException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace ReDI
{
public class InjectingServiceNotRegisteredException : Exception
{
private readonly Type _serviceType;
private readonly Type _injectingType;

public InjectingServiceNotRegisteredException(Type serviceType, Type injectingType)
{
_serviceType = serviceType;
_injectingType = injectingType;
}

public override string Message { get => $"Not found service of type {_injectingType}, required for service {_serviceType}"; }
}
}
16 changes: 16 additions & 0 deletions ReDI/Exceptions/ModuleInstanceAlreadyRegisteredException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace ReDI
{
public class ModuleInstanceAlreadyRegisteredException : Exception
{
private readonly Module _module;

public ModuleInstanceAlreadyRegisteredException(Module module)
{
_module = module;
}

public override string Message { get => $"Instance of module {_module.GetType()} already registered"; }
}
}
16 changes: 16 additions & 0 deletions ReDI/Exceptions/ModuleNotAssignedException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace ReDI
{
public class ModuleNotAssignedException : Exception
{
private readonly Type _moduleType;

public ModuleNotAssignedException(Type moduleType)
{
_moduleType = moduleType;
}

public override string Message { get => $"Not find module instance of {_moduleType}, probably null registration"; }
}
}
13 changes: 13 additions & 0 deletions ReDI/Exceptions/NotFoundInjectingConstructorException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace ReDI
{
public class NotFoundInjectingConstructorException : Exception
{
private readonly Type _type;

public NotFoundInjectingConstructorException(Type type) { _type = type; }

public override string Message { get => $"Not found constructor with [Inject] attribute, multiple constructor's defined in {_type}"; }
}
}
13 changes: 13 additions & 0 deletions ReDI/Exceptions/SecondCallBuildServiceInternalException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace ReDI
{
public class SecondCallBuildServiceInternalException : Exception
{
private readonly Type _type;

public SecondCallBuildServiceInternalException(Type type) { _type = type; }

public override string Message { get => $"Build of serivce {_type} was called second time"; }
}
}
13 changes: 13 additions & 0 deletions ReDI/Exceptions/TooManyInjectingConstructorsException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace ReDI
{
public class TooManyInjectingConstructorsException: Exception
{
private readonly Type _type;

public TooManyInjectingConstructorsException(Type type) { _type = type; }

public override string Message { get => $"{_type} contain more than 1 constructor with injecting attributes"; }
}
}
10 changes: 10 additions & 0 deletions ReDI/InjectAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace ReDI
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Constructor | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class InjectAttribute : Attribute
{

}
}
2 changes: 1 addition & 1 deletion Remouse.DI/Module.cs → ReDI/Module.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Remouse.DI
namespace ReDI
{
public abstract class Module
{
Expand Down
Loading

0 comments on commit bbddd22

Please sign in to comment.