Mercurial > pub > ImplabNet
view Implab.ServiceHost/Unity/TypeReference.cs @ 281:e0916ddc9950 v3 tip
code cleanup and refactoring
author | cin |
---|---|
date | Fri, 01 Jun 2018 21:35:24 +0300 |
parents | 6691aff01de1 |
children |
line wrap: on
line source
using System; using System.Linq; using System.Text; namespace Implab.ServiceHost.Unity { /// <summary> /// Ссылка на тип, является абстрактной записью имени CLR типа. /// </summary> /// <remarks> /// Ссылка на тип содержит сокращенную информацию о типе и для ее интерпретации /// требуется некоторый контекст, который позволит превратить ее в полноценный /// <see cref="Type"/>. Ссылки на тип позволяют записать: /// <list> /// <item><description>общие типы, их специализации</description></item> /// <item><description>вложенные типы</description></item> /// <item><description>массивы</description></item> /// </list> /// <para> /// Для получения из ссылки на тип конкретного CLR типа используется <see cref="TypeResolver.Resolve(TypeReference, bool)"/>. /// </para> /// <para> /// Ссылку на тип можно создать либо програмно при помощи методов <see cref="Create(string, string, int)"/>, /// <see cref="Create(string, int)"/>, <see cref="MakeArrayType(int)"/>, <see cref="MakeGenericType(TypeReference[])"/>, /// либо разобрав строку со спецификацией при помощи метода <see cref="Parse(string)"/>. /// </para> /// <para> /// Спецификация ссыдки на тип имеет следующий вид <c>Name.Space.MyType+Nested{String}[][]</c>, где: /// <list type="table"> /// <item> /// <term><c>.</c></term> /// <description>Разделяет элементы пространства имен</description> /// <item> /// <item> /// <term><c>+</c></term> /// <description>Разделяет вложенные типы</description> /// <item> /// <item> /// <term><c>[]</c>, <c>[,,,]</c></term> /// <description>Указывает на то, что тип является массивом, также указывается его размерность</description> /// <item> /// <item> /// <term><c>{}</c>, <c>{,,}</c>, <c>{Int32,String}</c></term> /// <description>Указывает на то, что тип является общим, также /// указывается количество параметров, либо конкретные типы для /// специализации</description> /// <item> /// </list> /// </para> /// </remarks> public abstract class TypeReference { /// <summary> /// Имя типа без дополнительных элементов, указывающих на то, что он общий или массив. /// </summary> /// <remarks> /// Для массивов это имя его элементов. /// </remarks> public abstract string Name { get; } /// <summary> /// Пространство имен в котором нахожится тип. /// </summary> /// <remarks> /// Для вложенных типов это пространтство имен типа самого верхнего уровня, /// для массивов - пространство имен его элементов. /// </remarks> public abstract string Namespace { get; } /// <summary> /// Количество параметров общего типа. /// </summary> /// <remarks> /// <para> /// Вложенные типы неявно получают параметры от типов в которых они объявлены, /// данное свойство это не учитывает, возвращается только количество собственных /// параметров. /// </para> /// <para> /// Данное свойство используется для получения CRL имени типа. /// </para> /// </remarks> public abstract int GenericParametersCount { get; } public virtual string ClrName { get { return GenericParametersCount != 0 ? $"{Name}`{GenericParametersCount}" : Name; } } /// <summary> /// Создает ссылку на специализацию текущего типа. /// </summary> /// <param name="genericParameters">Ссылки на типы, которые будут использоваться для специализации текущего типа.</param> /// <returns>Специализация данного типа.</returns> public virtual SpecializedTypeReference MakeGenericType(TypeReference[] genericParameters) { if (GenericParametersCount == 0) throw new InvalidOperationException("Can't specialize a non-geneic type"); if (genericParameters == null || GenericParametersCount != genericParameters.Length) throw new InvalidOperationException("Generic parameters count mismatch"); return new SpecializedTypeReference(this, genericParameters); } /// <summary> /// Создает ссылку на тип массива указанной размерности, элементами которого являются экземпаляры даннго типа. /// </summary> /// <param name="rank">Размерность, если размерность <c>1</c> создается вектор (<see cref="Type.MakeArrayType()"/>).</param> /// <returns>Ссылка на тип массива</returns> public ArrayTypeReference MakeArrayType(int rank) { Safe.ArgumentInRange(rank > 0, nameof(rank)); return new ArrayTypeReference(this, rank); } /// <summary> /// Создает ссылку на вложенный тип. /// </summary> /// <param name="name">Имя типа</param> /// <param name="genericParameters">Количество параметров, если это общий тип, иначе 0.</param> /// <returns>Ссылка на вложенный тип.</returns> public TypeReference Create(string name, int genericParameters) { Safe.ArgumentNotEmpty(name, nameof(name)); Safe.ArgumentInRange(genericParameters >= 0, nameof(genericParameters)); return new NestedTypeReference(this, name, genericParameters); } /// <summary> /// Возвращает строковое представление ссылки на тип. /// </summary> /// <returns></returns> public override string ToString() { var builder = new StringBuilder(); WriteTypeName(builder); WriteTypeParams(builder); return builder.ToString(); } internal virtual void WriteTypeName(StringBuilder builder) { if (!string.IsNullOrEmpty(Namespace)) builder .Append(Namespace) .Append('.'); builder.Append(Name); } internal virtual void WriteTypeParams(StringBuilder builder) { if (GenericParametersCount > 0) builder .Append('{') .Append(',', GenericParametersCount-1) .Append('}'); } internal abstract void Visit(TypeResolutionContext visitor); /// <summary> /// Создает ссылку на тип. /// </summary> /// <param name="ns">Пространство имен, либо его фрагмент.</param> /// <param name="name">Имя типа без указания на количество параметров, либо на то, что это массив.</param> /// <param name="genericParameters">Количество параметров типа, если это общий тип, иначе 0.</param> /// <returns>Ссылка на тип.</returns> public static TypeReference Create(string ns, string name, int genericParameters) { Safe.ArgumentNotEmpty(name, nameof(name)); Safe.ArgumentInRange(genericParameters >= 0, nameof(genericParameters)); return new RootTypeReference(ns, name, genericParameters); } /// <summary> /// Разирает строковую запись ссылки на тип. /// </summary> /// <param name="typeSpec">Строковая запись ссылки на тип, например <c>Dictionary{String,String}</c></param> /// <returns>Ссылка на тип.</returns> public static TypeReference Parse(string typeSpec) { var parser = new TypeReferenceParser(typeSpec); return parser.Parse(); } } }