TypeReference.cs
181 lines
| 9.2 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r289 | 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(); | |||
} | |||
} | |||
} |