CreationContext
Used during a component request, passed along to the whole process.
This allow some data to be passed along the process, which is used
to detected cycled dependency graphs and now it's also being used
to provide arguments to components.
using Castle.Core;
using Castle.MicroKernel.Releasers;
using Castle.MicroKernel.SubSystems.Conversion;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Castle.MicroKernel.Context
{
[Serializable]
public class CreationContext : MarshalByRefObject, ISubDependencyResolver
{
public class ResolutionContext : IDisposable
{
private readonly Burden burden;
private readonly CreationContext context;
public Burden Burden => burden;
public ResolutionContext(CreationContext context, Burden burden)
{
this.context = context;
this.burden = burden;
}
public void Dispose()
{
context.ExitResolutionContext(burden);
}
}
private readonly ITypeConverter converter;
private readonly DependencyModelCollection dependencies;
private readonly Type[] genericArguments;
private readonly IHandler handler;
private readonly Stack<IHandler> handlerStack = new Stack<IHandler>();
private readonly IReleasePolicy releasePolicy;
private readonly Stack<ResolutionContext> resolutionStack = new Stack<ResolutionContext>();
private IDictionary additionalParameters;
private IDictionary extendedProperties;
public IDictionary AdditionalParameters {
get {
if (additionalParameters == null)
additionalParameters = new Arguments();
return additionalParameters;
}
}
public DependencyModelCollection Dependencies => dependencies;
public Type[] GenericArguments => genericArguments;
public IHandler Handler => handler;
public bool HasAdditionalParameters {
get {
if (additionalParameters != null)
return additionalParameters.Count != 0;
return false;
}
}
public IReleasePolicy ReleasePolicy => releasePolicy;
public static CreationContext Empty => new CreationContext();
public CreationContext(Type typeToExtractGenericArguments, CreationContext parentContext, bool propagateInlineDependencies)
: this(parentContext.Handler, parentContext.ReleasePolicy, typeToExtractGenericArguments, null, null, parentContext)
{
if (parentContext == null)
throw new ArgumentNullException("parentContext");
if (parentContext.extendedProperties != null) {
extendedProperties = new Dictionary<object, object>(parentContext.extendedProperties.Count);
IDictionaryEnumerator enumerator = parentContext.extendedProperties.GetEnumerator();
try {
while (enumerator.MoveNext()) {
DictionaryEntry dictionaryEntry = (DictionaryEntry)enumerator.Current;
extendedProperties.Add(dictionaryEntry.Key, dictionaryEntry.Value);
}
} finally {
(enumerator as IDisposable)?.Dispose();
}
}
if (propagateInlineDependencies && parentContext.HasAdditionalParameters)
additionalParameters = new Arguments(parentContext.additionalParameters);
}
public CreationContext(IHandler handler, IReleasePolicy releasePolicy, Type typeToExtractGenericArguments, IDictionary additionalArguments, ITypeConverter conversionManager, CreationContext parent)
{
this.handler = handler;
this.releasePolicy = releasePolicy;
additionalParameters = EnsureAdditionalArgumentsWriteable(additionalArguments);
converter = conversionManager;
dependencies = new DependencyModelCollection();
genericArguments = ExtractGenericArguments(typeToExtractGenericArguments);
if (parent != null) {
resolutionStack = parent.resolutionStack;
dependencies.AddRange(parent.Dependencies);
foreach (IHandler item in parent.handlerStack) {
handlerStack.Push(item);
}
}
}
private CreationContext()
{
dependencies = new DependencyModelCollection();
releasePolicy = new NoTrackingReleasePolicy();
}
public void AddContextualProperty(object key, object value)
{
if (key == null)
throw new ArgumentNullException("key");
if (extendedProperties == null)
extendedProperties = new Dictionary<object, object>();
extendedProperties.Add(key, value);
}
public ResolutionContext EnterResolutionContext(IHandler handlerBeingResolved)
{
return EnterResolutionContext(handlerBeingResolved, true);
}
public ResolutionContext EnterResolutionContext(IHandler handlerBeingResolved, bool createBurden)
{
ResolutionContext resolutionContext = new ResolutionContext(this, createBurden ? new Burden() : null);
handlerStack.Push(handlerBeingResolved);
if (createBurden)
resolutionStack.Push(resolutionContext);
return resolutionContext;
}
public object GetContextualProperty(object key)
{
if (extendedProperties == null)
return null;
return extendedProperties[key];
}
public bool IsInResolutionContext(IHandler handler)
{
return handlerStack.Contains(handler);
}
public virtual bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
if (additionalParameters == null)
return false;
bool flag = CanResolveByKey(dependency);
bool result = CanResolveByType(dependency);
if (!flag)
return result;
return true;
}
public virtual object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
object obj = additionalParameters[dependency.DependencyKey];
Type targetItemType = dependency.TargetItemType;
if (obj != null) {
if (converter != null && !targetItemType.IsInstanceOfType(obj) && dependency.DependencyType == DependencyType.Parameter)
return converter.PerformConversion(obj.ToString(), targetItemType);
return obj;
}
obj = additionalParameters[targetItemType];
if (obj != null && converter != null && !targetItemType.IsInstanceOfType(obj) && dependency.DependencyType == DependencyType.Parameter)
return converter.PerformConversion(obj.ToString(), targetItemType);
return obj;
}
private bool CanResolve(DependencyModel dependency, object inlineArgument)
{
Type targetItemType = dependency.TargetItemType;
if (inlineArgument == null || (object)targetItemType == null)
return false;
if (!targetItemType.IsInstanceOfType(inlineArgument)) {
if (converter != null && dependency.DependencyType == DependencyType.Parameter)
return converter.CanHandleType(targetItemType);
return false;
}
return true;
}
private bool CanResolveByKey(DependencyModel dependency)
{
if (dependency.DependencyKey == null)
return false;
return CanResolve(dependency, additionalParameters[dependency.DependencyKey]);
}
private bool CanResolveByType(DependencyModel dependency)
{
Type targetItemType = dependency.TargetItemType;
if ((object)targetItemType == null)
return false;
return CanResolve(dependency, additionalParameters[targetItemType]);
}
private IDictionary EnsureAdditionalArgumentsWriteable(IDictionary dictionary)
{
if (dictionary == null)
return null;
if (!(dictionary is ReflectionBasedDictionaryAdapter))
return dictionary;
return new Arguments(dictionary);
}
private void ExitResolutionContext(Burden burden)
{
handlerStack.Pop();
if (burden != null) {
resolutionStack.Pop();
if (resolutionStack.Count != 0)
resolutionStack.Peek().Burden.AddChild(burden);
}
}
private static Type[] ExtractGenericArguments(Type typeToExtractGenericArguments)
{
return typeToExtractGenericArguments.GetGenericArguments();
}
}
}