Mercurial > pub > ImplabNet
diff Implab.ServiceHost/Unity/TypeReference.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 | 0be8a6ae8307 |
children |
line wrap: on
line diff
--- a/Implab.ServiceHost/Unity/TypeReference.cs Sat Apr 28 18:48:09 2018 +0300 +++ b/Implab.ServiceHost/Unity/TypeReference.cs Thu May 03 09:59:44 2018 +0300 @@ -3,56 +3,180 @@ using System.Text; namespace Implab.ServiceHost.Unity { - public class TypeReference { - public string TypeName { get; set; } - - public string Namespace { get; set; } - - public TypeReference[] GenericParameters { get; set; } - - public bool IsArray { get; set; } + /// <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 { - public bool IsOpenGeneric { + /// <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 GenericParameters!=null && GenericParameters.Contains(null); - } - } - - public bool IsGeneric { - get { - return GenericParameters != null && GenericParameters.Length > 0; + 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(); - - if (!string.IsNullOrEmpty(Namespace)) { - builder.Append(Namespace); - builder.Append('.'); - } - - if (!string.IsNullOrEmpty(TypeName)) { - builder.Append(TypeName); - } else { - builder.Append("__unnamed__"); - } - - if (GenericParameters != null && GenericParameters.Length > 0) { - builder.Append('{'); - for(var i = 0; i < GenericParameters.Length; i++) { - if (i > 0) - builder.Append(','); - builder.Append(GenericParameters[i]); - } - builder.Append('}'); - } - + WriteTypeName(builder); + WriteTypeParams(builder); return builder.ToString(); } - public static TypeReference Parse(string text) { - var parser = new TypeReferenceParser(text); + + 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(); } + } } \ No newline at end of file