TypeResolver.cs
124 lines
| 4.2 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r270 | using System; | |
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Text.RegularExpressions; | |||
using Implab.Diagnostics; | |||
cin
|
r277 | namespace Implab.ServiceHost.Unity { | |
cin
|
r270 | using static Trace<TypeResolver>; | |
cin
|
r277 | public class TypeResolver { | |
cin
|
r270 | 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) { | |||
cin
|
r272 | m_parent = parent; | |
cin
|
r270 | 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; | |||
cin
|
r277 | if (!m_cache.TryGetValue(reference.ToString(), out resolved)) { | |
cin
|
r270 | resolved = ResolveInternal(reference, args, argc); | |
if (resolved == null) | |||
throw new Exception($"Failed to resolve {reference}"); | |||
m_cache[reference.ToString()] = resolved; | |||
} | |||
return resolved; | |||
} | |||
cin
|
r272 | public Type Resolve(string typeSpec) { | |
return Resolve(TypeReference.Parse(typeSpec)); | |||
} | |||
cin
|
r270 | Type ResolveInternal(TypeReference reference, Type[] args, int argc) { | |
var resolved = ProbeInNamespaces( | |||
cin
|
r277 | String.Join(".", new[] { reference.Namespace, reference.TypeName }.Where(x => !string.IsNullOrEmpty(x))), | |
cin
|
r270 | args, | |
argc, | |||
reference.IsArray, | |||
reference.ToString() | |||
); | |||
if (resolved == null && m_parent != null) | |||
cin
|
r277 | resolved = m_parent.ResolveInternal(reference, args, argc); | |
cin
|
r270 | return resolved; | |
} | |||
public Type ProbeInNamespaces(string localName, Type[] args, int argc, bool isArray, string referenceName) { | |||
foreach (var ns in m_namespases) { | |||
cin
|
r277 | var typeName = FormatName(new[] { ns, localName }, argc); | |
cin
|
r270 | ||
var resolved = Probe(typeName); | |||
if (resolved != null) { | |||
cin
|
r277 | if (args != null && args.Length > 0) { | |
resolved = resolved.MakeGenericType(args); | |||
} | |||
if (isArray) | |||
resolved = resolved.MakeArrayType(); | |||
cin
|
r270 | 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(); | |||
cin
|
r277 | foreach (var assembly in assemblies) { | |
cin
|
r270 | var type = assembly.GetType(typeName); | |
if (type != null) | |||
return type; | |||
} | |||
return null; | |||
} | |||
cin
|
r277 | string FormatName(string[] parts, int argc) { | |
cin
|
r270 | var builder = new StringBuilder(); | |
cin
|
r277 | ||
cin
|
r270 | builder.Append(String.Join(".", parts.Where(x => !string.IsNullOrEmpty(x)))); | |
if (argc > 0) { | |||
builder.Append('`'); | |||
builder.Append(argc); | |||
} | |||
cin
|
r277 | return builder.ToString(); | |
cin
|
r270 | } | |
} | |||
} |