diff --git a/BattleFieldSimulator/BattleFieldSimulator.Utilities/BattleFieldSimulator.Utilities.csproj b/BattleFieldSimulator/BattleFieldSimulator.Utilities/BattleFieldSimulator.Utilities.csproj
deleted file mode 100644
index 6091e1b..0000000
--- a/BattleFieldSimulator/BattleFieldSimulator.Utilities/BattleFieldSimulator.Utilities.csproj
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
- Debug
- AnyCPU
- {F65ECA33-08FF-4797-8E53-B086320214F4}
- Library
- Properties
- BattleFieldSimulator.Utilities
- BattleFieldSimulator.Utilities
- v4.7.2
- 512
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.
-
-
-
-
-
\ No newline at end of file
diff --git a/BattleFieldSimulator/BattleFieldSimulator.Utilities/BootStrapper.cs b/BattleFieldSimulator/BattleFieldSimulator.Utilities/BootStrapper.cs
deleted file mode 100644
index 0d5eeaf..0000000
--- a/BattleFieldSimulator/BattleFieldSimulator.Utilities/BootStrapper.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using DryIoc;
-
-namespace BattleFieldSimulator
-{
- public class BootStrapper
- {
- private static readonly string NoBootstrapperMessage = $"Called {nameof(BootStrapper)} before it existed";
-
- private static BootStrapper _bootStrapper;
- private static IContainer _container;
-
- public static BootStrapper Instance =>
- _bootStrapper ?? throw new InvalidOperationException(NoBootstrapperMessage);
-
- private BootStrapper(params IModule[] modules)
- {
- _container = new Container();
- foreach (var module in modules)
- {
- module.Register(_container);
- }
- foreach (var module in modules)
- {
- module.Resolve(_container);
- }
- }
-
- public static BootStrapper BootstrapSystem(params IModule[] modules) =>
- _bootStrapper = new BootStrapper(modules);
-
- public T Resolve()
- {
- return _container.Resolve();
- }
- }
-}
\ No newline at end of file
diff --git a/BattleFieldSimulator/BattleFieldSimulator.Utilities/Class1.cs b/BattleFieldSimulator/BattleFieldSimulator.Utilities/Class1.cs
deleted file mode 100644
index 33b2880..0000000
--- a/BattleFieldSimulator/BattleFieldSimulator.Utilities/Class1.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace BattleFieldSimulator.Utilities
-{
- public class Class1
- {
- }
-}
\ No newline at end of file
diff --git a/BattleFieldSimulator/BattleFieldSimulator.Utilities/DryIoc/Container.cs b/BattleFieldSimulator/BattleFieldSimulator.Utilities/DryIoc/Container.cs
deleted file mode 100644
index 6f30561..0000000
--- a/BattleFieldSimulator/BattleFieldSimulator.Utilities/DryIoc/Container.cs
+++ /dev/null
@@ -1,14042 +0,0 @@
-//
-/*
-The MIT License (MIT)
-
-Copyright (c) 2013-2020 Maksim Volkau
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-#if !PCL && !NET35 && !NET40 && !NET403 && !NETSTANDARD1_0 && !NETSTANDARD1_1 && !NETSTANDARD1_2 && !NETCOREAPP1_0 && !NETCOREAPP1_1
-#define SUPPORTS_FAST_EXPRESSION_COMPILER
-#endif
-#if !PCL && !NET35 && !NET40 && !NET403 && !NETSTANDARD1_0 && !NETSTANDARD1_1 && !NETSTANDARD1_2 && !NETSTANDARD1_3 && !NETSTANDARD1_4 && !NETSTANDARD1_5 && !NETSTANDARD1_6 && !NETCOREAPP1_0 && !NETCOREAPP1_1
-#define SUPPORTS_ISERVICE_PROVIDER
-#endif
-#if !PCL && !NETSTANDARD1_0 && !NETSTANDARD1_1 && !NETSTANDARD1_2 && !NETSTANDARD1_3 && !NETSTANDARD1_4 && !NETSTANDARD1_5 && !NETSTANDARD1_6
-#define SUPPORTS_SERIALIZABLE
-#define SUPPORTS_STACK_TRACE
-#define SUPPORTS_MANAGED_THREAD_ID
-#endif
-#if !PCL && !NETSTANDARD1_0 && !NETSTANDARD1_1 && !NETSTANDARD1_2 && !NETSTANDARD1_3 && !NETSTANDARD1_5 && !NET35 && !NET40 && !NET403 && !NET45 && !NET451 && !NET452
-#define SUPPORTS_ASYNC_LOCAL
-#endif
-#if !PCL && !NETSTANDARD1_0 && !NETSTANDARD1_1 && !NETSTANDARD1_2 && !NET35 && !NET40 && !NET403
-#define SUPPORTS_VARIANCE
-#endif
-#if !PCL && !NET35 && !NET40 && !NET403 && !NET45 && !NET451 && !NET452 && !NET46 && !NET461 && !NET462 && !NET47 && !NET471 && !NET472 && !NETSTANDARD1_0 && !NETSTANDARD1_1 && !NETSTANDARD1_2 && !NETSTANDARD1_3 && !NETSTANDARD1_4
-#define SUPPORTS_EXPRESSION_COMPILE_WITH_PREFER_INTERPRETATION_PARAM
-#endif
-#if !PCL && !NET35 && !NET40 && !NET403
-#define SUPPORTS_DELEGATE_METHOD
-#endif
-
-namespace DryIoc
-{
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- using System.Text;
- using System.Threading;
- using System.Diagnostics.CodeAnalysis; // for SuppressMessage
- using System.Diagnostics; // for StackTrace
- using System.Runtime.CompilerServices; // for MethodImplAttribute
-
- using ImTools;
- using static ImTools.ArrayTools;
- using static System.Environment;
-
- using ExprType = System.Linq.Expressions.ExpressionType;
-
-#if SUPPORTS_FAST_EXPRESSION_COMPILER
- using FastExpressionCompiler.LightExpression;
- using static FastExpressionCompiler.LightExpression.Expression;
-#else
- using System.Linq.Expressions;
- using static System.Linq.Expressions.Expression;
-#endif
-
- /// Inversion of control container
- public sealed partial class Container : IContainer
- {
- /// Creates new container with default rules .
- public Container() : this(Rules.Default, Ref.Of(Registry.Default), NewSingletonScope())
- {
- SetInitialFactoryID();
- }
-
- /// Creates new container, optionally providing to modify default container behavior.
- /// (optional) Rules to modify container default resolution behavior.
- /// If not specified, then will be used.
- /// (optional) Scope context to use for scoped reuse.
- public Container(Rules rules = null, IScopeContext scopeContext = null)
- : this(rules ?? Rules.Default, Ref.Of(Registry.Default), NewSingletonScope(), scopeContext)
- {
- SetInitialFactoryID();
- }
-
- /// Creates new container with configured rules.
- /// Allows to modify rules.
- /// (optional) Scope context to use for .
- public Container(Func configure, IScopeContext scopeContext = null)
- : this(configure.ThrowIfNull()(Rules.Default) ?? Rules.Default, scopeContext)
- { }
-
- private sealed class SinlgetonScopeName
- {
- public static readonly SinlgetonScopeName Name = new SinlgetonScopeName();
- private SinlgetonScopeName() { }
- public override string ToString() => nameof(SinlgetonScopeName);
- }
-
- /// Helper to create singleton scope
- public static IScope NewSingletonScope() => new Scope(name: SinlgetonScopeName.Name);
-
- /// Pretty prints the container info including the open scope details if any.
- public override string ToString()
- {
- var s = _scopeContext == null ? "Container" : "Container with ambient ScopeContext " + _scopeContext;
-
- var scope = CurrentScope;
- s += scope == null ? " without Scope" : " with Scope " + scope;
-
- if (Rules != Rules.Default)
- s += NewLine + " with " + Rules;
-
- if (IsDisposed)
- {
- s += " has been DISPOSED!" + NewLine;
- if (_disposeStackTrace != null)
- s += " Dispose stack-trace " + _disposeStackTrace;
- else
- s += " You may include Dispose stack-trace into the message via:" + NewLine +
- "container.With(rules => rules.WithCaptureContainerDisposeStackTrace())";
- }
-
- return s;
- }
-
- /// Dispose either open scope, or container with singletons, if no scope opened.
- public void Dispose()
- {
- // if already disposed - just leave
- if (Interlocked.CompareExchange(ref _disposed, 1, 0) == 1)
- return;
-
- // Nice to have disposal stack-trace, but we can live without it if something goes wrong
- if (Rules.CaptureContainerDisposeStackTrace)
- try { _disposeStackTrace = new StackTrace(); }
- catch { }
-
- if (_parent != null)
- {
- if (_ownCurrentScope != null)
- {
- _ownCurrentScope.Dispose();
- }
- else if (_scopeContext != null)
- {
- IScope currentScope = null;
- _scopeContext.SetCurrent(s =>
- {
- // save the current scope for the later,
- // do dispose it AFTER its parent is actually set to be a new ambient current scope.
- currentScope = s;
- return s?.Parent;
- });
- currentScope?.Dispose();
- }
- }
- else
- {
- _registry.Swap(Registry.Empty);
- Rules = Rules.Default;
- _singletonScope.Dispose(); // will also dispose any tracked scopes
- _scopeContext?.Dispose();
- }
- }
-
- #region Compile-time generated parts - former DryIocZero
-
- partial void GetLastGeneratedFactoryID(ref int lastFactoryID);
-
- partial void ResolveGenerated(ref object service, Type serviceType);
-
- partial void ResolveGenerated(ref object service,
- Type serviceType, object serviceKey, Type requiredServiceType, Request preRequestParent, object[] args);
-
- partial void ResolveManyGenerated(ref IEnumerable services, Type serviceType);
-
- /// Identifies the service when resolving collection
- public struct ResolveManyResult
- {
- /// Factory, the required part
- public FactoryDelegate FactoryDelegate;
-
- /// Optional key
- public object ServiceKey;
-
- /// Optional required service type, can be an open-generic type.
- public Type RequiredServiceType;
-
- /// Constructs the struct.
- public static ResolveManyResult Of(FactoryDelegate factoryDelegate,
- object serviceKey = null, Type requiredServiceType = null) =>
- new ResolveManyResult
- {
- FactoryDelegate = factoryDelegate,
- ServiceKey = serviceKey,
- RequiredServiceType = requiredServiceType
- };
- }
-
- /// Directly uses generated factories to resolve service. Or returns the default if service does not have generated factory.
- [SuppressMessage("ReSharper", "InvocationIsSkipped", Justification = "Per design")]
- [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "Per design")]
- public object ResolveCompileTimeGeneratedOrDefault(Type serviceType)
- {
- object service = null;
- ResolveGenerated(ref service, serviceType);
- return service;
- }
-
- /// Directly uses generated factories to resolve service. Or returns the default if service does not have generated factory.
- [SuppressMessage("ReSharper", "InvocationIsSkipped", Justification = "Per design")]
- [SuppressMessage("ReSharper", "ExpressionIsAlwaysNull", Justification = "Per design")]
- public object ResolveCompileTimeGeneratedOrDefault(Type serviceType, object serviceKey)
- {
- object service = null;
- ResolveGenerated(ref service, serviceType, serviceKey,
- requiredServiceType: null, preRequestParent: null, args: null);
- return service;
- }
-
- /// Resolves many generated only services. Ignores runtime registrations.
- public IEnumerable ResolveManyCompileTimeGeneratedOrEmpty(Type serviceType)
- {
- IEnumerable manyGenerated = ArrayTools.Empty();
- ResolveManyGenerated(ref manyGenerated, serviceType);
- return manyGenerated;
- }
-
- #endregion
-
- #region IRegistrator
-
- /// Returns all registered service factories with their Type and optional Key.
- /// Decorator and Wrapper types are not included.
- public IEnumerable GetServiceRegistrations() =>
- _registry.Value.GetServiceRegistrations();
-
- // todo: Make `serviceKey` and `factoryType` optional
- /// Searches for registered factories by type, and key (if specified),
- /// and by factory type (by default uses ).
- /// May return empty, 1 or multiple factories.
- public Factory[] GetRegisteredFactories(Type serviceType, object serviceKey, FactoryType factoryType) =>
- _registry.Value.GetRegisteredFactories(serviceType.ThrowIfNull(), serviceKey, factoryType);
-
- /// Stores factory into container using and as key
- /// for later lookup.
- /// Any subtypes of .
- /// Type of service to resolve later.
- /// (optional) Service key of any type with and
- /// implemented.
- /// (optional) Says how to handle existing registration with the same
- /// and .
- /// Confirms that service and implementation types are statically checked by compiler.
- /// True if factory was added to registry, false otherwise.
- /// False may be in case of setting and already existing factory.
- public void Register(Factory factory, Type serviceType, object serviceKey, IfAlreadyRegistered? ifAlreadyRegistered, bool isStaticallyChecked)
- {
- ThrowIfContainerDisposed();
-
- if (serviceKey == null)
- serviceKey = Rules.DefaultRegistrationServiceKey;
-
- factory.ThrowIfNull().ValidateAndNormalizeRegistration(serviceType, serviceKey, isStaticallyChecked, Rules);
-
- if (!ifAlreadyRegistered.HasValue)
- ifAlreadyRegistered = Rules.DefaultIfAlreadyRegistered;
-
- // Improves performance a bit by first attempting to swap the registry while it is still unchanged.
- var r = _registry.Value;
- if (!_registry.TrySwapIfStillCurrent(r, r.Register(factory, serviceType, ifAlreadyRegistered.Value, serviceKey)))
- RegistrySwap(factory, serviceType, serviceKey, ifAlreadyRegistered);
- }
-
- // hiding nested lambda in method to reduce allocations
- private Registry RegistrySwap(Factory factory, Type serviceType, object serviceKey, IfAlreadyRegistered? ifAlreadyRegistered) =>
- _registry.Swap(r => r.Register(factory, serviceType, ifAlreadyRegistered.Value, serviceKey));
-
- ///
- public bool IsRegistered(Type serviceType, object serviceKey, FactoryType factoryType, Func condition)
- {
- ThrowIfContainerDisposed();
- return _registry.Value.IsRegistered(serviceType, serviceKey, factoryType, condition);
- }
-
- ///
- public void Unregister(Type serviceType, object serviceKey, FactoryType factoryType, Func condition)
- {
- ThrowIfContainerDisposed();
- _registry.Swap(r => r.Unregister(factoryType, serviceType, serviceKey, condition));
- }
-
-#endregion
-
-#region IResolver
-
-#if SUPPORTS_ISERVICE_PROVIDER
- /// Resolves service with policy,
- /// enabling the fallback resolution for not registered services (default MS convention)
- object IServiceProvider.GetService(Type serviceType) =>
- ((IResolver)this).Resolve(serviceType, IfUnresolved.ReturnDefaultIfNotRegistered);
-#endif
-
- object IResolver.Resolve(Type serviceType, IfUnresolved ifUnresolved)
- {
- object service = null;
- ResolveGenerated(ref service, serviceType);
- if (service != null)
- return service;
-
- var serviceTypeHash = RuntimeHelpers.GetHashCode(serviceType);
- var cacheEntry = _registry.Value.GetCachedDefaultFactoryOrDefault(serviceTypeHash, serviceType);
- if (cacheEntry != null)
- {
- ref var entry = ref cacheEntry.Value;
- if (entry.Value is FactoryDelegate cachedDelegate)
- return cachedDelegate(this);
-
- if (ResolverContext.TryGetUsedInstance(this, serviceType, out var usedInstance))
- {
- entry.Value = null; // reset the cache
- return usedInstance;
- }
-
- var rules = Rules;
- while (entry.Value is Expression expr)
- {
- if (rules.UseInterpretation &&
- Interpreter.TryInterpretAndUnwrapContainerException(this, expr, false, out var result))
- return result;
-
- // set to Compiling to notify other threads to use the interpretation until the service is compiled
- if (Interlocked.CompareExchange(ref entry.Value, new Registry.Compiling(expr), expr) == expr)
- {
- var compiledFactory = expr.CompileToFactoryDelegate(rules.UseFastExpressionCompiler, rules.UseInterpretation);
- // todo: should we instead cache only after invoking the factory delegate
- entry.Value = compiledFactory;
- return compiledFactory(this);
- }
- }
-
- if (entry.Value is Registry.Compiling compiling)
- {
- if (Interpreter.TryInterpretAndUnwrapContainerException(this, compiling.Expression, false, out var result))
- return result;
- return compiling.Expression.CompileToFactoryDelegate(rules.UseFastExpressionCompiler, rules.UseInterpretation)(this);
- }
- }
-
- return ResolveAndCache(serviceTypeHash, serviceType, ifUnresolved);
- }
-
- private object ResolveAndCache(int serviceTypeHash, Type serviceType, IfUnresolved ifUnresolved)
- {
- ThrowIfContainerDisposed();
-
- if (ResolverContext.TryGetUsedInstance(this, serviceType, out var usedInstance))
- return usedInstance;
-
- var request = Request.Create(this, serviceType, ifUnresolved: ifUnresolved);
- var factory = ((IContainer)this).ResolveFactory(request); // HACK: may mutate request, but it should be safe
-
- // Delegate to full blown Resolve aware of service key, open scope, etc.
- var serviceKey = request.ServiceKey;
- var scopeName = CurrentScope?.Name;
- if (serviceKey != null || scopeName != null)
- return ResolveAndCacheKeyed(serviceTypeHash, serviceType, serviceKey, ifUnresolved, scopeName, null, Request.Empty, null);
-
- if (factory == null)
- return null;
-
- var rules = Rules;
- FactoryDelegate factoryDelegate;
-
- // todo: [Obsolete] - in v5.0 there should be no check nor the InstanceFactory
- if (factory is InstanceFactory ||
- !rules.UseInterpretationForTheFirstResolution)
- {
- factoryDelegate = factory.GetDelegateOrDefault(request);
- if (factoryDelegate == null)
- return null;
- }
- else
- {
- var expr = factory.GetExpressionOrDefault(request);
- if (expr == null)
- return null;
-
- if (expr is ConstantExpression constExpr)
- {
- var value = constExpr.Value;
- if (factory.Caching != FactoryCaching.DoNotCache)
- _registry.Value.TryCacheDefaultFactory(serviceTypeHash, serviceType, value.ToFactoryDelegate);
- return value;
- }
-
- // Important to cache expression first before tying to interpret,
- // so that parallel resolutions may already use it and UseInstance may correctly evict the cache if needed.
- if (factory.Caching != FactoryCaching.DoNotCache)
- _registry.Value.TryCacheDefaultFactory(serviceTypeHash, serviceType, expr);
-
- // 1) First try to interpret
- if (Interpreter.TryInterpretAndUnwrapContainerException(this, expr, rules.UseFastExpressionCompiler, out var instance))
- return instance;
- // 2) Fallback to expression compilation
- factoryDelegate = expr.CompileToFactoryDelegate(rules.UseFastExpressionCompiler, rules.UseInterpretation);
- }
-
- if (factory.Caching != FactoryCaching.DoNotCache)
- _registry.Value.TryCacheDefaultFactory(serviceTypeHash, serviceType, factoryDelegate);
-
- return factoryDelegate(this);
- }
-
- object IResolver.Resolve(Type serviceType, object serviceKey,
- IfUnresolved ifUnresolved, Type requiredServiceType, Request preResolveParent, object[] args)
- {
- // fallback to simple Resolve and its default cache if no keys are passed
- var scopeName = CurrentScope?.Name;
- if (serviceKey == null && requiredServiceType == null && scopeName == null &&
- (preResolveParent == null || preResolveParent.IsEmpty) && args.IsNullOrEmpty())
- return ((IResolver)this).Resolve(serviceType, ifUnresolved);
-
- return ResolveAndCacheKeyed(RuntimeHelpers.GetHashCode(serviceType), serviceType,
- serviceKey, ifUnresolved, scopeName, requiredServiceType, preResolveParent ?? Request.Empty, args);
- }
-
- private object ResolveAndCacheKeyed(int serviceTypeHash, Type serviceType,
- object serviceKey, IfUnresolved ifUnresolved, object scopeName, Type requiredServiceType, Request preResolveParent,
- object[] args)
- {
- object service = null;
- ResolveGenerated(ref service, serviceType, serviceKey, requiredServiceType, preResolveParent, args);
- if (service != null)
- return service;
-
- object cacheKey = null;
- if (requiredServiceType == null && preResolveParent.IsEmpty && args.IsNullOrEmpty())
- {
- cacheKey = scopeName == null ? serviceKey
- : serviceKey == null ? scopeName
- : KV.Of(scopeName, serviceKey);
-
- if (_registry.Value.GetCachedKeyedFactoryOrDefault(serviceTypeHash, serviceType, cacheKey, out var cacheEntry))
- {
- if (cacheEntry.Factory is FactoryDelegate cachedDelegate)
- return cachedDelegate(this);
- if (TryInterpretOrCompileCachedExpression(this, cacheEntry, Rules, out var result))
- return result;
- }
- }
-
- // Cache is missed, so get the factory and put it into cache:
- ThrowIfContainerDisposed();
-
- var request = Request.Create(this, serviceType, serviceKey, ifUnresolved, requiredServiceType, preResolveParent, default, args);
- var factory = ((IContainer)this).ResolveFactory(request);
- if (factory == null)
- return null;
-
- // Prevents caching if factory says Don't
- if (factory.Caching == FactoryCaching.DoNotCache)
- cacheKey = null;
-
- // Request service key may be changed when resolving the factory,
- // so we need to look into Default cache again for the new key
- if (cacheKey != null && serviceKey == null && request.ServiceKey != null)
- {
- cacheKey = scopeName == null ? request.ServiceKey : KV.Of(scopeName, request.ServiceKey);
- if (_registry.Value.GetCachedKeyedFactoryOrDefault(serviceTypeHash, serviceType, cacheKey, out var cacheEntry))
- {
- if (cacheEntry.Factory is FactoryDelegate cachedDelegate)
- return cachedDelegate(this);
- if (TryInterpretOrCompileCachedExpression(this, cacheEntry, Rules, out var result))
- return result;
- }
- }
-
- FactoryDelegate factoryDelegate;
- if (factory is InstanceFactory || !Rules.UseInterpretationForTheFirstResolution)
- {
- factoryDelegate = factory.GetDelegateOrDefault(request);
- if (factoryDelegate == null)
- return null;
- }
- else
- {
- var expr = factory.GetExpressionOrDefault(request);
- if (expr == null)
- return null;
-
- if (expr is ConstantExpression constExpr)
- {
- var value = constExpr.Value;
- if (cacheKey != null)
- _registry.Value.TryCacheKeyedFactory(serviceTypeHash, serviceType, cacheKey, (FactoryDelegate)value.ToFactoryDelegate);
- return value;
- }
-
- // Important to cache expression first before tying to interpret,
- // so that parallel resolutions may already use it and UseInstance may correctly evict the cache if needed
- if (cacheKey != null)
- _registry.Value.TryCacheKeyedFactory(serviceTypeHash, serviceType, cacheKey, expr);
-
- // 1) First try to interpret
- var useFec = Rules.UseFastExpressionCompiler;
- if (Interpreter.TryInterpretAndUnwrapContainerException(this, expr, useFec, out var instance))
- return instance;
-
- // 2) Fallback to expression compilation
- factoryDelegate = expr.CompileToFactoryDelegate(useFec, Rules.UseInterpretation);
- }
-
- // Cache factory only when we successfully called the factory delegate, to prevent failing delegates to be cached.
- // Additionally disable caching when no services registered, not to cache an empty collection wrapper or alike.
- if (cacheKey != null)
- _registry.Value.TryCacheKeyedFactory(serviceTypeHash, serviceType, cacheKey, factoryDelegate);
-
- return factoryDelegate(this);
- }
-
- private static bool TryInterpretOrCompileCachedExpression(IResolverContext r,
- Registry.KeyedFactoryCacheEntry cacheEntry, Rules rules, out object result)
- {
- while (cacheEntry.Factory is Expression expr)
- {
- if (rules.UseInterpretation &&
- Interpreter.TryInterpretAndUnwrapContainerException(r, expr, false, out result))
- return true;
-
- // set to Compiling to notify other threads to use the interpretation until the service is compiled
- if (Interlocked.CompareExchange(ref cacheEntry.Factory, new Registry.Compiling(expr), expr) == expr)
- {
- var factoryDelegate = expr.CompileToFactoryDelegate(rules.UseFastExpressionCompiler, rules.UseInterpretation);
- // todo: should we instead cache only after invoking the factory delegate
- cacheEntry.Factory = factoryDelegate;
- result = factoryDelegate(r);
- return true;
- }
- }
-
- if (cacheEntry.Factory is Registry.Compiling compiling)
- {
- if (!Interpreter.TryInterpretAndUnwrapContainerException(r, compiling.Expression, false, out result))
- result = compiling.Expression.CompileToFactoryDelegate(rules.UseFastExpressionCompiler, rules.UseInterpretation)(r);
- return true;
- }
-
- result = null;
- return false;
- }
-
- IEnumerable