comparison 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
comparison
equal deleted inserted replaced
277:963b17c275be 278:6691aff01de1
1 using System; 1 using System;
2 using System.Linq; 2 using System.Linq;
3 using System.Text; 3 using System.Text;
4 4
5 namespace Implab.ServiceHost.Unity { 5 namespace Implab.ServiceHost.Unity {
6 public class TypeReference { 6 /// <summary>
7 public string TypeName { get; set; } 7 /// Ссылка на тип, является абстрактной записью имени CLR типа.
8 /// </summary>
9 /// <remarks>
10 /// Ссылка на тип содержит сокращенную информацию о типе и для ее интерпретации
11 /// требуется некоторый контекст, который позволит превратить ее в полноценный
12 /// <see cref="Type"/>. Ссылки на тип позволяют записать:
13 /// <list>
14 /// <item><description>общие типы, их специализации</description></item>
15 /// <item><description>вложенные типы</description></item>
16 /// <item><description>массивы</description></item>
17 /// </list>
18 /// <para>
19 /// Для получения из ссылки на тип конкретного CLR типа используется <see cref="TypeResolver.Resolve(TypeReference, bool)"/>.
20 /// </para>
21 /// <para>
22 /// Ссылку на тип можно создать либо програмно при помощи методов <see cref="Create(string, string, int)"/>,
23 /// <see cref="Create(string, int)"/>, <see cref="MakeArrayType(int)"/>, <see cref="MakeGenericType(TypeReference[])"/>,
24 /// либо разобрав строку со спецификацией при помощи метода <see cref="Parse(string)"/>.
25 /// </para>
26 /// <para>
27 /// Спецификация ссыдки на тип имеет следующий вид <c>Name.Space.MyType+Nested{String}[][]</c>, где:
28 /// <list type="table">
29 /// <item>
30 /// <term><c>.</c></term>
31 /// <description>Разделяет элементы пространства имен</description>
32 /// <item>
33 /// <item>
34 /// <term><c>+</c></term>
35 /// <description>Разделяет вложенные типы</description>
36 /// <item>
37 /// <item>
38 /// <term><c>[]</c>, <c>[,,,]</c></term>
39 /// <description>Указывает на то, что тип является массивом, также указывается его размерность</description>
40 /// <item>
41 /// <item>
42 /// <term><c>{}</c>, <c>{,,}</c>, <c>{Int32,String}</c></term>
43 /// <description>Указывает на то, что тип является общим, также
44 /// указывается количество параметров, либо конкретные типы для
45 /// специализации</description>
46 /// <item>
47 /// </list>
48 /// </para>
49 /// </remarks>
50 public abstract class TypeReference {
8 51
9 public string Namespace { get; set; } 52 /// <summary>
53 /// Имя типа без дополнительных элементов, указывающих на то, что он общий или массив.
54 /// </summary>
55 /// <remarks>
56 /// Для массивов это имя его элементов.
57 /// </remarks>
58 public abstract string Name { get; }
10 59
11 public TypeReference[] GenericParameters { get; set; } 60 /// <summary>
61 /// Пространство имен в котором нахожится тип.
62 /// </summary>
63 /// <remarks>
64 /// Для вложенных типов это пространтство имен типа самого верхнего уровня,
65 /// для массивов - пространство имен его элементов.
66 /// </remarks>
67 public abstract string Namespace { get; }
12 68
13 public bool IsArray { get; set; } 69 /// <summary>
70 /// Количество параметров общего типа.
71 /// </summary>
72 /// <remarks>
73 /// <para>
74 /// Вложенные типы неявно получают параметры от типов в которых они объявлены,
75 /// данное свойство это не учитывает, возвращается только количество собственных
76 /// параметров.
77 /// </para>
78 /// <para>
79 /// Данное свойство используется для получения CRL имени типа.
80 /// </para>
81 /// </remarks>
82 public abstract int GenericParametersCount { get; }
14 83
15 public bool IsOpenGeneric { 84 public virtual string ClrName {
16 get { 85 get {
17 return GenericParameters!=null && GenericParameters.Contains(null); 86 return GenericParametersCount != 0 ? $"{Name}`{GenericParametersCount}" : Name;
18 } 87 }
19 } 88 }
20 89
21 public bool IsGeneric { 90 /// <summary>
22 get { 91 /// Создает ссылку на специализацию текущего типа.
23 return GenericParameters != null && GenericParameters.Length > 0; 92 /// </summary>
24 } 93 /// <param name="genericParameters">Ссылки на типы, которые будут использоваться для специализации текущего типа.</param>
94 /// <returns>Специализация данного типа.</returns>
95 public virtual SpecializedTypeReference MakeGenericType(TypeReference[] genericParameters) {
96 if (GenericParametersCount == 0)
97 throw new InvalidOperationException("Can't specialize a non-geneic type");
98
99 if (genericParameters == null || GenericParametersCount != genericParameters.Length)
100 throw new InvalidOperationException("Generic parameters count mismatch");
101
102 return new SpecializedTypeReference(this, genericParameters);
25 } 103 }
26 104
105 /// <summary>
106 /// Создает ссылку на тип массива указанной размерности, элементами которого являются экземпаляры даннго типа.
107 /// </summary>
108 /// <param name="rank">Размерность, если размерность <c>1</c> создается вектор (<see cref="Type.MakeArrayType()"/>).</param>
109 /// <returns>Ссылка на тип массива</returns>
110 public ArrayTypeReference MakeArrayType(int rank) {
111 Safe.ArgumentInRange(rank > 0, nameof(rank));
112
113 return new ArrayTypeReference(this, rank);
114 }
115
116 /// <summary>
117 /// Создает ссылку на вложенный тип.
118 /// </summary>
119 /// <param name="name">Имя типа</param>
120 /// <param name="genericParameters">Количество параметров, если это общий тип, иначе 0.</param>
121 /// <returns>Ссылка на вложенный тип.</returns>
122 public TypeReference Create(string name, int genericParameters) {
123 Safe.ArgumentNotEmpty(name, nameof(name));
124 Safe.ArgumentInRange(genericParameters >= 0, nameof(genericParameters));
125
126 return new NestedTypeReference(this, name, genericParameters);
127 }
128
129 /// <summary>
130 /// Возвращает строковое представление ссылки на тип.
131 /// </summary>
132 /// <returns></returns>
27 public override string ToString() { 133 public override string ToString() {
28 var builder = new StringBuilder(); 134 var builder = new StringBuilder();
29 135 WriteTypeName(builder);
30 if (!string.IsNullOrEmpty(Namespace)) { 136 WriteTypeParams(builder);
31 builder.Append(Namespace);
32 builder.Append('.');
33 }
34
35 if (!string.IsNullOrEmpty(TypeName)) {
36 builder.Append(TypeName);
37 } else {
38 builder.Append("__unnamed__");
39 }
40
41 if (GenericParameters != null && GenericParameters.Length > 0) {
42 builder.Append('{');
43 for(var i = 0; i < GenericParameters.Length; i++) {
44 if (i > 0)
45 builder.Append(',');
46 builder.Append(GenericParameters[i]);
47 }
48 builder.Append('}');
49 }
50
51 return builder.ToString(); 137 return builder.ToString();
52 } 138 }
53 public static TypeReference Parse(string text) { 139
54 var parser = new TypeReferenceParser(text); 140 internal virtual void WriteTypeName(StringBuilder builder) {
141 if (!string.IsNullOrEmpty(Namespace))
142 builder
143 .Append(Namespace)
144 .Append('.');
145 builder.Append(Name);
146 }
147
148 internal virtual void WriteTypeParams(StringBuilder builder) {
149 if (GenericParametersCount > 0)
150 builder
151 .Append('{')
152 .Append(',', GenericParametersCount-1)
153 .Append('}');
154 }
155
156 internal abstract void Visit(TypeResolutionContext visitor);
157
158 /// <summary>
159 /// Создает ссылку на тип.
160 /// </summary>
161 /// <param name="ns">Пространство имен, либо его фрагмент.</param>
162 /// <param name="name">Имя типа без указания на количество параметров, либо на то, что это массив.</param>
163 /// <param name="genericParameters">Количество параметров типа, если это общий тип, иначе 0.</param>
164 /// <returns>Ссылка на тип.</returns>
165 public static TypeReference Create(string ns, string name, int genericParameters) {
166 Safe.ArgumentNotEmpty(name, nameof(name));
167 Safe.ArgumentInRange(genericParameters >= 0, nameof(genericParameters));
168 return new RootTypeReference(ns, name, genericParameters);
169 }
170
171 /// <summary>
172 /// Разирает строковую запись ссылки на тип.
173 /// </summary>
174 /// <param name="typeSpec">Строковая запись ссылки на тип, например <c>Dictionary{String,String}</c></param>
175 /// <returns>Ссылка на тип.</returns>
176 public static TypeReference Parse(string typeSpec) {
177 var parser = new TypeReferenceParser(typeSpec);
55 return parser.Parse(); 178 return parser.Parse();
56 } 179 }
180
57 } 181 }
58 } 182 }