TypeResolutionContext.cs
74 lines
| 2.7 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r278 | 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; | |||
} | |||
} | |||
} |