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