|
|
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();
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|