Mercurial > pub > ImplabNet
comparison Implab.ServiceHost/Unity/TypeResolver.cs @ 278:6691aff01de1 v3
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)
Implab.ServiceHost: rewritten TypeReference (added support for nested types), stable API
| author | cin |
|---|---|
| date | Thu, 03 May 2018 09:59:44 +0300 |
| parents | 963b17c275be |
| children | 8714471e8d78 |
comparison
equal
deleted
inserted
replaced
| 277:963b17c275be | 278:6691aff01de1 |
|---|---|
| 4 using System.Text; | 4 using System.Text; |
| 5 using System.Text.RegularExpressions; | 5 using System.Text.RegularExpressions; |
| 6 using Implab.Diagnostics; | 6 using Implab.Diagnostics; |
| 7 | 7 |
| 8 namespace Implab.ServiceHost.Unity { | 8 namespace Implab.ServiceHost.Unity { |
| 9 using System.Diagnostics; | |
| 9 using static Trace<TypeResolver>; | 10 using static Trace<TypeResolver>; |
| 10 public class TypeResolver { | 11 public class TypeResolver { |
| 11 readonly Dictionary<string, Type> m_cache = new Dictionary<string, Type>(); | 12 readonly Dictionary<string, Type> m_cache = new Dictionary<string, Type>(); |
| 12 | 13 |
| 13 Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled); | 14 Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled); |
| 14 readonly LinkedList<string> m_namespases = new LinkedList<string>(); | 15 readonly LinkedList<string> m_namespases = new LinkedList<string>(); |
| 15 | 16 |
| 17 internal Type Resolve(string ns, string typeName) { | |
| 18 var fullName = string.IsNullOrEmpty(ns) ? typeName : $"{ns}.{typeName}"; | |
| 19 | |
| 20 return ProbeInNamespaces(fullName); | |
| 21 } | |
| 22 | |
| 23 public Type Resolve(TypeReference typeReference, bool throwOnFail) { | |
| 24 var context = new TypeResolutionContext(this, throwOnFail); | |
| 25 typeReference.Visit(context); | |
| 26 return context.MakeType(); | |
| 27 } | |
| 28 | |
| 29 public Type Resolve(string typeSpec, bool throwOnFail) { | |
| 30 var typeReference = TypeReference.Parse(typeSpec); | |
| 31 return Resolve(typeReference, throwOnFail); | |
| 32 } | |
| 33 | |
| 16 LinkedListNode<string> m_insertAt; | 34 LinkedListNode<string> m_insertAt; |
| 17 | 35 |
| 18 readonly TypeResolver m_parent; | 36 readonly TypeResolver m_parent; |
| 19 | 37 |
| 20 public TypeResolver() : this(null) { | 38 public TypeResolver() : this(null) { |
| 21 | |
| 22 } | 39 } |
| 23 | 40 |
| 24 public TypeResolver(TypeResolver parent) { | 41 public TypeResolver(TypeResolver parent) { |
| 25 m_parent = parent; | 42 m_parent = parent; |
| 26 m_insertAt = new LinkedListNode<string>(string.Empty); | 43 m_insertAt = new LinkedListNode<string>(string.Empty); |
| 40 Safe.ArgumentNotNull(type, nameof(type)); | 57 Safe.ArgumentNotNull(type, nameof(type)); |
| 41 | 58 |
| 42 m_cache[typeName] = type; | 59 m_cache[typeName] = type; |
| 43 } | 60 } |
| 44 | 61 |
| 45 public Type Resolve(TypeReference reference) { | 62 Type ProbeInNamespaces(string localName) { |
| 46 var args = reference.IsGeneric && !reference.IsOpenGeneric ? reference.GenericParameters?.Select(Resolve).ToArray() : null; | |
| 47 var argc = reference.IsGeneric ? reference.GenericParameters.Length : 0; | |
| 48 | 63 |
| 49 Type resolved; | 64 Type resolved; |
| 50 if (!m_cache.TryGetValue(reference.ToString(), out resolved)) { | 65 if (!m_cache.TryGetValue(localName, out resolved)) { |
| 51 resolved = ResolveInternal(reference, args, argc); | 66 foreach (var ns in m_namespases) { |
| 52 if (resolved == null) | 67 var typeName = string.IsNullOrEmpty(ns) ? localName : $"{ns}.{localName}"; |
| 53 throw new Exception($"Failed to resolve {reference}"); | 68 resolved = Probe(typeName); |
| 54 m_cache[reference.ToString()] = resolved; | 69 if (resolved != null) { |
| 70 Log($"Probe '{localName}' -> '{resolved.FullName}'"); | |
| 71 break; | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 if (resolved == null && m_parent != null) | |
| 76 resolved = m_parent.ProbeInNamespaces(localName); | |
| 77 | |
| 78 if(resolved == null) | |
| 79 Log($"Probe '{localName}' failed"); | |
| 80 | |
| 81 m_cache[localName] = resolved; | |
| 55 } | 82 } |
| 56 | 83 |
| 57 return resolved; | 84 return resolved; |
| 58 } | |
| 59 | |
| 60 public Type Resolve(string typeSpec) { | |
| 61 return Resolve(TypeReference.Parse(typeSpec)); | |
| 62 } | |
| 63 | |
| 64 Type ResolveInternal(TypeReference reference, Type[] args, int argc) { | |
| 65 var resolved = ProbeInNamespaces( | |
| 66 String.Join(".", new[] { reference.Namespace, reference.TypeName }.Where(x => !string.IsNullOrEmpty(x))), | |
| 67 args, | |
| 68 argc, | |
| 69 reference.IsArray, | |
| 70 reference.ToString() | |
| 71 ); | |
| 72 | |
| 73 if (resolved == null && m_parent != null) | |
| 74 resolved = m_parent.ResolveInternal(reference, args, argc); | |
| 75 | |
| 76 return resolved; | |
| 77 } | |
| 78 | |
| 79 public Type ProbeInNamespaces(string localName, Type[] args, int argc, bool isArray, string referenceName) { | |
| 80 foreach (var ns in m_namespases) { | |
| 81 var typeName = FormatName(new[] { ns, localName }, argc); | |
| 82 | |
| 83 var resolved = Probe(typeName); | |
| 84 if (resolved != null) { | |
| 85 if (args != null && args.Length > 0) { | |
| 86 resolved = resolved.MakeGenericType(args); | |
| 87 } | |
| 88 | |
| 89 if (isArray) | |
| 90 resolved = resolved.MakeArrayType(); | |
| 91 | |
| 92 Log("Probe succeed {0} in '{1}': {2} -> {3}", referenceName, ns, typeName, resolved.AssemblyQualifiedName); | |
| 93 return resolved; | |
| 94 } else { | |
| 95 Log("Probe failed {0} in '{1}': {2}", referenceName, ns, typeName); | |
| 96 } | |
| 97 } | |
| 98 | |
| 99 return null; | |
| 100 } | 85 } |
| 101 | 86 |
| 102 Type Probe(string typeName) { | 87 Type Probe(string typeName) { |
| 103 var assemblies = AppDomain.CurrentDomain.GetAssemblies(); | 88 var assemblies = AppDomain.CurrentDomain.GetAssemblies(); |
| 104 | 89 |
| 107 if (type != null) | 92 if (type != null) |
| 108 return type; | 93 return type; |
| 109 } | 94 } |
| 110 return null; | 95 return null; |
| 111 } | 96 } |
| 112 | |
| 113 string FormatName(string[] parts, int argc) { | |
| 114 var builder = new StringBuilder(); | |
| 115 | |
| 116 builder.Append(String.Join(".", parts.Where(x => !string.IsNullOrEmpty(x)))); | |
| 117 if (argc > 0) { | |
| 118 builder.Append('`'); | |
| 119 builder.Append(argc); | |
| 120 } | |
| 121 | |
| 122 return builder.ToString(); | |
| 123 } | |
| 124 } | 97 } |
| 125 } | 98 } |
