Mercurial > pub > ImplabNet
comparison 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 |
comparison
equal
deleted
inserted
replaced
269:ff581cff7003 | 270:ade80d94dfb5 |
---|---|
1 using System; | |
2 using System.Collections.Generic; | |
3 using System.Linq; | |
4 using System.Text; | |
5 using System.Text.RegularExpressions; | |
6 using Implab.Diagnostics; | |
7 | |
8 namespace Implab.ServiceHost.Unity | |
9 { | |
10 using static Trace<TypeResolver>; | |
11 public class TypeResolver | |
12 { | |
13 readonly Dictionary<string, Type> m_cache = new Dictionary<string, Type>(); | |
14 | |
15 Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled); | |
16 readonly LinkedList<string> m_namespases = new LinkedList<string>(); | |
17 | |
18 LinkedListNode<string> m_insertAt; | |
19 | |
20 readonly TypeResolver m_parent; | |
21 | |
22 public TypeResolver() : this(null) { | |
23 | |
24 } | |
25 | |
26 public TypeResolver(TypeResolver parent) { | |
27 m_insertAt = new LinkedListNode<string>(string.Empty); | |
28 m_namespases.AddFirst(m_insertAt); | |
29 } | |
30 | |
31 public void AddNamespace(string ns) { | |
32 Safe.ArgumentMatch(ns, nameof(ns), _nsRx); | |
33 if (m_insertAt != null) | |
34 m_namespases.AddAfter(m_insertAt, ns); | |
35 else | |
36 m_namespases.AddFirst(ns); | |
37 } | |
38 | |
39 public void AddMapping(string typeName, Type type) { | |
40 Safe.ArgumentNotEmpty(typeName, nameof(typeName)); | |
41 Safe.ArgumentNotNull(type, nameof(type)); | |
42 | |
43 m_cache[typeName] = type; | |
44 } | |
45 | |
46 public Type Resolve(TypeReference reference) { | |
47 var args = reference.IsGeneric && !reference.IsOpenGeneric ? reference.GenericParameters?.Select(Resolve).ToArray() : null; | |
48 var argc = reference.IsGeneric ? reference.GenericParameters.Length : 0; | |
49 | |
50 Type resolved; | |
51 if(!m_cache.TryGetValue(reference.ToString(), out resolved)) { | |
52 resolved = ResolveInternal(reference, args, argc); | |
53 if (resolved == null) | |
54 throw new Exception($"Failed to resolve {reference}"); | |
55 m_cache[reference.ToString()] = resolved; | |
56 } | |
57 | |
58 return resolved; | |
59 } | |
60 | |
61 Type ResolveInternal(TypeReference reference, Type[] args, int argc) { | |
62 var resolved = ProbeInNamespaces( | |
63 String.Join(".", new [] { reference.Namespace, reference.TypeName }.Where(x => !string.IsNullOrEmpty(x)) ), | |
64 args, | |
65 argc, | |
66 reference.IsArray, | |
67 reference.ToString() | |
68 ); | |
69 | |
70 if (resolved == null && m_parent != null) | |
71 resolved = m_parent.Resolve(reference); | |
72 | |
73 return resolved; | |
74 } | |
75 | |
76 public Type ProbeInNamespaces(string localName, Type[] args, int argc, bool isArray, string referenceName) { | |
77 foreach (var ns in m_namespases) { | |
78 var typeName = FormatName(new [] { ns, localName}, argc, args, isArray); | |
79 | |
80 var resolved = Probe(typeName); | |
81 if (resolved != null) { | |
82 Log("Probe succeed {0} in '{1}': {2} -> {3}", referenceName, ns, typeName, resolved.AssemblyQualifiedName); | |
83 return resolved; | |
84 } else { | |
85 Log("Probe failed {0} in '{1}': {2}", referenceName, ns, typeName); | |
86 } | |
87 } | |
88 | |
89 return null; | |
90 } | |
91 | |
92 Type Probe(string typeName) { | |
93 var assemblies = AppDomain.CurrentDomain.GetAssemblies(); | |
94 | |
95 foreach(var assembly in assemblies) { | |
96 var type = assembly.GetType(typeName); | |
97 if (type != null) | |
98 return type; | |
99 } | |
100 return null; | |
101 } | |
102 | |
103 string FormatName(string[] parts, int argc, Type[] args, bool isArray) { | |
104 var builder = new StringBuilder(); | |
105 | |
106 builder.Append(String.Join(".", parts.Where(x => !string.IsNullOrEmpty(x)))); | |
107 if (argc > 0) { | |
108 builder.Append('`'); | |
109 builder.Append(argc); | |
110 } | |
111 | |
112 if (args!= null && args.Length > 0) { | |
113 builder.Append('['); | |
114 builder.Append(string.Join(",", args.Select(x => $"[{x.AssemblyQualifiedName}]"))); | |
115 builder.Append(']'); | |
116 } | |
117 | |
118 if(isArray) | |
119 builder.Append("[]"); | |
120 | |
121 return builder.ToString(); | |
122 } | |
123 } | |
124 } |