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 }