using System;
using System.Linq;
using System.Text;
namespace Implab.ServiceHost.Unity {
///
/// Ссылка на тип, является абстрактной записью имени CLR типа.
///
///
/// Ссылка на тип содержит сокращенную информацию о типе и для ее интерпретации
/// требуется некоторый контекст, который позволит превратить ее в полноценный
/// . Ссылки на тип позволяют записать:
///
/// - общие типы, их специализации
/// - вложенные типы
/// - массивы
///
///
/// Для получения из ссылки на тип конкретного CLR типа используется .
///
///
/// Ссылку на тип можно создать либо програмно при помощи методов ,
/// , , ,
/// либо разобрав строку со спецификацией при помощи метода .
///
///
/// Спецификация ссыдки на тип имеет следующий вид Name.Space.MyType+Nested{String}[][], где:
///
/// -
/// .
/// Разделяет элементы пространства имен
///
-
///
-
/// +
/// Разделяет вложенные типы
///
-
///
-
/// [], [,,,]
/// Указывает на то, что тип является массивом, также указывается его размерность
///
-
///
-
/// {}, {,,}, {Int32,String}
/// Указывает на то, что тип является общим, также
/// указывается количество параметров, либо конкретные типы для
/// специализации
///
-
///
///
///
public abstract class TypeReference {
///
/// Имя типа без дополнительных элементов, указывающих на то, что он общий или массив.
///
///
/// Для массивов это имя его элементов.
///
public abstract string Name { get; }
///
/// Пространство имен в котором нахожится тип.
///
///
/// Для вложенных типов это пространтство имен типа самого верхнего уровня,
/// для массивов - пространство имен его элементов.
///
public abstract string Namespace { get; }
///
/// Количество параметров общего типа.
///
///
///
/// Вложенные типы неявно получают параметры от типов в которых они объявлены,
/// данное свойство это не учитывает, возвращается только количество собственных
/// параметров.
///
///
/// Данное свойство используется для получения CRL имени типа.
///
///
public abstract int GenericParametersCount { get; }
public virtual string ClrName {
get {
return GenericParametersCount != 0 ? $"{Name}`{GenericParametersCount}" : Name;
}
}
///
/// Создает ссылку на специализацию текущего типа.
///
/// Ссылки на типы, которые будут использоваться для специализации текущего типа.
/// Специализация данного типа.
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);
}
///
/// Создает ссылку на тип массива указанной размерности, элементами которого являются экземпаляры даннго типа.
///
/// Размерность, если размерность 1 создается вектор ().
/// Ссылка на тип массива
public ArrayTypeReference MakeArrayType(int rank) {
Safe.ArgumentInRange(rank > 0, nameof(rank));
return new ArrayTypeReference(this, rank);
}
///
/// Создает ссылку на вложенный тип.
///
/// Имя типа
/// Количество параметров, если это общий тип, иначе 0.
/// Ссылка на вложенный тип.
public TypeReference Create(string name, int genericParameters) {
Safe.ArgumentNotEmpty(name, nameof(name));
Safe.ArgumentInRange(genericParameters >= 0, nameof(genericParameters));
return new NestedTypeReference(this, name, genericParameters);
}
///
/// Возвращает строковое представление ссылки на тип.
///
///
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);
///
/// Создает ссылку на тип.
///
/// Пространство имен, либо его фрагмент.
/// Имя типа без указания на количество параметров, либо на то, что это массив.
/// Количество параметров типа, если это общий тип, иначе 0.
/// Ссылка на тип.
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);
}
///
/// Разирает строковую запись ссылки на тип.
///
/// Строковая запись ссылки на тип, например Dictionary{String,String}
/// Ссылка на тип.
public static TypeReference Parse(string typeSpec) {
var parser = new TypeReferenceParser(typeSpec);
return parser.Parse();
}
}
}