tools/AutoMapper/ResolutionContext.cs (99 lines of code) (raw):

using System; using System.Collections.Generic; namespace AutoMapper { /// <summary> /// Context information regarding resolution of a destination value /// </summary> public class ResolutionContext { private Dictionary<ContextCacheKey, object> _instanceCache; private Dictionary<TypePair, int> _typeDepth; /// <summary> /// Mapping operation options /// </summary> public IMappingOperationOptions Options { get; } internal object GetDestination(object source, Type destinationType) { InstanceCache.TryGetValue(new ContextCacheKey(source, destinationType), out object destination); return destination; } internal void CacheDestination(object source, Type destinationType, object destination) { InstanceCache[new ContextCacheKey(source, destinationType)] = destination; } /// <summary> /// Instance cache for resolving circular references /// </summary> public Dictionary<ContextCacheKey, object> InstanceCache { get { CheckDefault(); if(_instanceCache != null) { return _instanceCache; } _instanceCache = new Dictionary<ContextCacheKey, object>(); return _instanceCache; } } private void CheckDefault() { if(IsDefault) { throw new InvalidOperationException(); } } /// <summary> /// Instance cache for resolving keeping track of depth /// </summary> private Dictionary<TypePair, int> TypeDepth { get { CheckDefault(); if(_typeDepth != null) { return _typeDepth; } _typeDepth = new Dictionary<TypePair, int>(); return _typeDepth; } } internal void IncrementTypeDepth(TypePair types) { TypeDepth[types]++; } internal void DecrementTypeDepth(TypePair types) { TypeDepth[types]--; } internal int GetTypeDepth(TypePair types) { if (!TypeDepth.ContainsKey(types)) TypeDepth[types] = 1; return TypeDepth[types]; } /// <summary> /// Current mapper /// </summary> public IRuntimeMapper Mapper { get; } /// <summary> /// Current configuration /// </summary> public IConfigurationProvider ConfigurationProvider => Mapper.ConfigurationProvider; /// <summary> /// Context items from <see cref="Options"/> /// </summary> public IDictionary<string, object> Items => Options.Items; public ResolutionContext(IMappingOperationOptions options, IRuntimeMapper mapper) { Options = options; Mapper = mapper; } internal bool IsDefault => this == Mapper.DefaultContext; internal TDestination Map<TSource, TDestination>(TSource source, TDestination destination) => Mapper.Map(source, destination, this); internal object Map(object source, object destination, Type sourceType, Type destinationType) => Mapper.Map(source, destination, sourceType, destinationType, this); internal void ValidateMap(TypeMap typeMap) => ConfigurationProvider.AssertConfigurationIsValid(typeMap); } public struct ContextCacheKey : IEquatable<ContextCacheKey> { public static bool operator ==(ContextCacheKey left, ContextCacheKey right) => left.Equals(right); public static bool operator !=(ContextCacheKey left, ContextCacheKey right) => !left.Equals(right); private readonly object _source; private readonly Type _destinationType; public ContextCacheKey(object source, Type destinationType) { _source = source; _destinationType = destinationType; } public override int GetHashCode() => HashCodeCombiner.Combine(_source, _destinationType); public bool Equals(ContextCacheKey other) => _source == other._source && _destinationType == other._destinationType; public override bool Equals(object other) => other is ContextCacheKey && Equals((ContextCacheKey)other); } }