Mercurial > pub > ImplabNet
diff Implab.ServiceHost/Unity/TypeResolutionContext.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 | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab.ServiceHost/Unity/TypeResolutionContext.cs Thu May 03 09:59:44 2018 +0300 @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using Implab.Diagnostics; + +namespace Implab.ServiceHost.Unity { + using static Trace<TypeResolver>; + + /// <summary> + /// Позволяет обойти вложенные типы и собрать цеочку из типов и параметров генериков, которые они предлагают + /// </summary> + internal class TypeResolutionContext { + readonly TypeResolver m_resolver; + + + readonly List<Type> m_genericParameters = new List<Type>(); + + public IEnumerable<Type> GenericParameters { get { return m_genericParameters; } } + + public Type ResolvedType { get; private set; } + + + public int ArrayRank { get; private set; } + + + public bool ThrowOnFail { get; private set; } + + public TypeResolutionContext(TypeResolver resolver, bool throwOnFail) { + m_resolver = resolver; + ThrowOnFail = throwOnFail; + } + + public Type MakeType() { + return m_genericParameters.Count > 0 ? + ResolvedType?.MakeGenericType(m_genericParameters.ToArray()) : + ResolvedType; + } + + public void Visit(SpecializedTypeReference typeReference) { + typeReference.GenericType.Visit(this); + + if (ResolvedType != null) { + foreach (var genericParamRef in typeReference.GenericParameters) { + var context = new TypeResolutionContext(m_resolver, ThrowOnFail); + genericParamRef.Visit(context); + m_genericParameters.Add(context.MakeType()); + } + } + } + + public void Visit(NestedTypeReference typeReference) { + typeReference.DeclaringType.Visit(this); + if (ResolvedType != null) + ResolvedType = ResolvedType?.GetNestedType(typeReference.ClrName) ?? Failed(typeReference); + } + + public void Visit(RootTypeReference typeReference) { + ResolvedType = m_resolver.Resolve(typeReference.Namespace, typeReference.ClrName) ?? Failed(typeReference); + } + + public void Visit(ArrayTypeReference typeReference) { + var context = new TypeResolutionContext(m_resolver, ThrowOnFail); + typeReference.ItemsType.Visit(context); + ResolvedType = typeReference.Rank == 1 ? + context.MakeType()?.MakeArrayType() : + context.MakeType()?.MakeArrayType(typeReference.Rank); + } + + Type Failed(TypeReference reference) { + Log($"Falied to resolve {reference}"); + if (ThrowOnFail) + throw new Exception($"Failed to resolve {reference}"); + return null; + } + } +} \ No newline at end of file