diff 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
line wrap: on
line diff
--- a/Implab.ServiceHost/Unity/TypeReference.cs	Sat Apr 28 18:48:09 2018 +0300
+++ b/Implab.ServiceHost/Unity/TypeReference.cs	Thu May 03 09:59:44 2018 +0300
@@ -3,56 +3,180 @@
 using System.Text;
 
 namespace Implab.ServiceHost.Unity {
-    public class TypeReference {
-        public string TypeName { get; set; }
-
-        public string Namespace { get; set; }
-
-        public TypeReference[] GenericParameters { get; set; }
-
-        public bool IsArray { get; set; }
+    /// <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 {
 
-        public bool IsOpenGeneric {
+        /// <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 GenericParameters!=null && GenericParameters.Contains(null);
-            }
-        }
-
-        public bool IsGeneric {
-            get {
-                return GenericParameters != null && GenericParameters.Length > 0;
+                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();
-
-            if (!string.IsNullOrEmpty(Namespace)) {
-                builder.Append(Namespace);
-                builder.Append('.');
-            }
-
-            if (!string.IsNullOrEmpty(TypeName)) {
-                builder.Append(TypeName);
-            } else {
-                builder.Append("__unnamed__");
-            }
-
-            if (GenericParameters != null && GenericParameters.Length > 0) {
-                builder.Append('{');
-                for(var i = 0; i < GenericParameters.Length; i++) {
-                    if (i > 0)
-                        builder.Append(',');
-                    builder.Append(GenericParameters[i]);
-                }
-                builder.Append('}');
-            }
-
+            WriteTypeName(builder);
+            WriteTypeParams(builder);
             return builder.ToString();
         }
-        public static TypeReference Parse(string text) {
-            var parser = new TypeReferenceParser(text);
+
+        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();
         }
+
     }
 }
\ No newline at end of file