Mercurial > pub > ImplabNet
diff Implab.ServiceHost/Unity/TypeResolver.cs @ 270:ade80d94dfb5 v3
Working on Unity container xml configuration
author | cin |
---|---|
date | Wed, 25 Apr 2018 04:44:40 +0300 |
parents | |
children | 9d1cca834b05 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab.ServiceHost/Unity/TypeResolver.cs Wed Apr 25 04:44:40 2018 +0300 @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Implab.Diagnostics; + +namespace Implab.ServiceHost.Unity +{ + using static Trace<TypeResolver>; + public class TypeResolver + { + readonly Dictionary<string, Type> m_cache = new Dictionary<string, Type>(); + + Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled); + readonly LinkedList<string> m_namespases = new LinkedList<string>(); + + LinkedListNode<string> m_insertAt; + + readonly TypeResolver m_parent; + + public TypeResolver() : this(null) { + + } + + public TypeResolver(TypeResolver parent) { + m_insertAt = new LinkedListNode<string>(string.Empty); + m_namespases.AddFirst(m_insertAt); + } + + public void AddNamespace(string ns) { + Safe.ArgumentMatch(ns, nameof(ns), _nsRx); + if (m_insertAt != null) + m_namespases.AddAfter(m_insertAt, ns); + else + m_namespases.AddFirst(ns); + } + + public void AddMapping(string typeName, Type type) { + Safe.ArgumentNotEmpty(typeName, nameof(typeName)); + Safe.ArgumentNotNull(type, nameof(type)); + + m_cache[typeName] = type; + } + + public Type Resolve(TypeReference reference) { + var args = reference.IsGeneric && !reference.IsOpenGeneric ? reference.GenericParameters?.Select(Resolve).ToArray() : null; + var argc = reference.IsGeneric ? reference.GenericParameters.Length : 0; + + Type resolved; + if(!m_cache.TryGetValue(reference.ToString(), out resolved)) { + resolved = ResolveInternal(reference, args, argc); + if (resolved == null) + throw new Exception($"Failed to resolve {reference}"); + m_cache[reference.ToString()] = resolved; + } + + return resolved; + } + + Type ResolveInternal(TypeReference reference, Type[] args, int argc) { + var resolved = ProbeInNamespaces( + String.Join(".", new [] { reference.Namespace, reference.TypeName }.Where(x => !string.IsNullOrEmpty(x)) ), + args, + argc, + reference.IsArray, + reference.ToString() + ); + + if (resolved == null && m_parent != null) + resolved = m_parent.Resolve(reference); + + return resolved; + } + + public Type ProbeInNamespaces(string localName, Type[] args, int argc, bool isArray, string referenceName) { + foreach (var ns in m_namespases) { + var typeName = FormatName(new [] { ns, localName}, argc, args, isArray); + + var resolved = Probe(typeName); + if (resolved != null) { + Log("Probe succeed {0} in '{1}': {2} -> {3}", referenceName, ns, typeName, resolved.AssemblyQualifiedName); + return resolved; + } else { + Log("Probe failed {0} in '{1}': {2}", referenceName, ns, typeName); + } + } + + return null; + } + + Type Probe(string typeName) { + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + + foreach(var assembly in assemblies) { + var type = assembly.GetType(typeName); + if (type != null) + return type; + } + return null; + } + + string FormatName(string[] parts, int argc, Type[] args, bool isArray) { + var builder = new StringBuilder(); + + builder.Append(String.Join(".", parts.Where(x => !string.IsNullOrEmpty(x)))); + if (argc > 0) { + builder.Append('`'); + builder.Append(argc); + } + + if (args!= null && args.Length > 0) { + builder.Append('['); + builder.Append(string.Join(",", args.Select(x => $"[{x.AssemblyQualifiedName}]"))); + builder.Append(']'); + } + + if(isArray) + builder.Append("[]"); + + return builder.ToString(); + } + } +} \ No newline at end of file