Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceReintegration/HeuristicLab.Persistence/3.3/Auxiliary/TypeName.cs @ 14927

Last change on this file since 14927 was 14927, checked in by gkronber, 7 years ago

#2520: changed all usages of StorableClass to use StorableType with an auto-generated GUID (did not add StorableType to other type definitions yet)

File size: 11.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Text;
26using HeuristicLab.Persistence;
27
28namespace HeuristicLab.Persistence.Auxiliary {
29
30  /// <summary>
31  /// Contains a more modular representation of type names that can
32  /// be used to compare versions and ignore extended assembly
33  /// attributes.
34  /// </summary>
35  [StorableType("a83d8580-07c2-4805-a31f-23b702689e0c")]
36  public class TypeName {
37
38    /// <summary>
39    /// Gets or sets the namespace.
40    /// </summary>
41    /// <value>The namespace.</value>
42    [Storable]
43    public string Namespace { get; private set; }
44
45    /// <summary>
46    /// Gets or sets the name of the class.
47    /// </summary>
48    /// <value>The name of the class.</value>
49    [Storable]
50    public string ClassName { get; private set; }
51
52    /// <summary>
53    /// Gets or sets the number of generic args for
54    /// each class in a series of nested classes.
55    /// </summary>
56    [Storable]
57    public List<int> GenericArgCounts { get; private set; }
58
59    /// <summary>
60    /// Gets or sets the generic args.
61    /// </summary>
62    /// <value>The generic args.</value>
63    [Storable]
64    public List<TypeName> GenericArgs { get; internal set; }
65
66    /// <summary>
67    /// Gets a value indicating whether this instance is generic.
68    /// </summary>
69    /// <value>
70    ///   <c>true</c> if this instance is generic; otherwise, <c>false</c>.
71    /// </value>
72    public bool IsGeneric { get { return GenericArgs.Count > 0; } }
73
74    /// <summary>
75    /// Gets or sets the memory magic (point or array declaration).
76    /// </summary>
77    /// <value>The memory magic.</value>
78    [Storable]
79    public string MemoryMagic { get; internal set; }
80
81    /// <summary>
82    /// Gets or sets the name of the assembly.
83    /// </summary>
84    /// <value>The name of the assembly.</value>
85    [Storable]
86    public string AssemblyName { get; internal set; }
87
88    /// <summary>
89    /// Gets or sets the assembly attribues.
90    /// </summary>
91    /// <value>The assembly attribues.</value>
92    [Storable]
93    public Dictionary<string, string> AssemblyAttribues { get; internal set; }
94
95    /// <summary>
96    /// Gets or sets a value indicating whether this instance is reference.
97    /// </summary>
98    /// <value>
99    ///   <c>true</c> if this instance is reference; otherwise, <c>false</c>.
100    /// </value>
101    [Storable]
102    public bool IsReference { get; internal set; }
103
104
105    [StorableConstructor]
106    protected TypeName(bool deserializing) { }
107    /// <summary>
108    /// Initializes a new instance of the <see cref="TypeName"/> class.
109    /// </summary>
110    /// <param name="nameSpace">The namespace.</param>
111    /// <param name="className">Name of the class.</param>
112    internal TypeName(string nameSpace, string className, List<int> genericArgCounts = null) {
113      Namespace = nameSpace;
114      ClassName = className;
115      GenericArgs = new List<TypeName>();
116      MemoryMagic = "";
117      AssemblyAttribues = new Dictionary<string, string>();
118      if (genericArgCounts != null)
119        GenericArgCounts = genericArgCounts.ToList();
120    }
121
122    internal TypeName(TypeName typeName, string className = null, string nameSpace = null) {
123      Namespace = nameSpace ?? typeName.Namespace;
124      ClassName = className ?? typeName.ClassName;
125      GenericArgs = new List<TypeName>(typeName.GenericArgs);
126      AssemblyAttribues = new Dictionary<string, string>(typeName.AssemblyAttribues);
127      MemoryMagic = typeName.MemoryMagic;
128      AssemblyName = typeName.AssemblyName;
129      IsReference = typeName.IsReference;
130      if (typeName.GenericArgCounts != null)
131        GenericArgCounts = typeName.GenericArgCounts.ToList();
132    }
133
134    /// <summary>
135    /// Returns a <see cref="System.String"/> that represents this instance.
136    /// </summary>
137    /// <param name="full">if set to <c>true</c> includes full information
138    /// about generic parameters and assembly properties.</param>
139    /// <returns>
140    /// A <see cref="System.String"/> that represents this instance.
141    /// </returns>
142    public string ToString(bool full) {
143      return ToString(full, true);
144    }
145
146
147    /// <summary>
148    /// Returns a <see cref="System.String"/> that represents this instance.
149    /// </summary>
150    /// <param name="full">if set to <c>true</c> includes full information
151    /// about generic parameters and assembly properties.</param>
152    /// <param name="includeAssembly">if set to <c>true</c> include assembly properties and generic parameters.</param>
153    /// <returns>
154    /// A <see cref="System.String"/> that represents this instance.
155    /// </returns>
156    public string ToString(bool full, bool includeAssembly) {
157      var sb = new StringBuilder();
158      if (!string.IsNullOrEmpty(Namespace))
159        sb.Append(Namespace).Append('.');
160      if (GenericArgCounts != null) {
161        sb.Append(string.Join("+",
162          ClassName
163          .Split('+')
164          .Zip(GenericArgCounts, (n, c) =>
165            c > 0 ? String.Format("{0}`{1}", n, c) : n)));
166      } else {
167        sb.Append(ClassName);
168        if (IsGeneric)
169          sb.Append('`').Append(GenericArgs.Count);
170      }
171      if (IsGeneric) {
172        sb.Append('[');
173        sb.Append(String.Join(",", GenericArgs.Select(a =>
174          string.Format("[{0}]", a.ToString(full)))));
175        sb.Append(']');
176      }
177      sb.Append(MemoryMagic);
178      if (includeAssembly && AssemblyName != null) {
179        sb.Append(", ").Append(AssemblyName);
180        if (full)
181          foreach (var property in AssemblyAttribues)
182            sb.Append(", ").Append(property.Key).Append('=').Append(property.Value);
183      }
184      return sb.ToString();
185    }
186
187    private IEnumerable<string> GetNestedClassesInCode(HashSet<string> omitNamespaces, bool includeAllNamespaces) {
188      var i = 0;
189      foreach (var pair in ClassName.Split('+').Zip(GenericArgCounts, (n, c) => new { n, c })) {
190        if (pair.c == 0) {
191          yield return pair.n;
192        } else {
193          yield return string.Format("{0}<{1}>",
194            pair.n,
195            string.Join(",",
196              GenericArgs
197                .GetRange(i, pair.c)
198                .Select(a => a.GetTypeNameInCode(omitNamespaces, includeAllNamespaces))));
199          i += pair.c;
200        }
201      }
202    }
203
204    private string GetTypeNameInCode(HashSet<string> omitNamespaces, bool includeNamespaces) {
205      var sb = new StringBuilder();
206      if (!string.IsNullOrEmpty(Namespace) &&
207            (omitNamespaces == null && includeNamespaces) ||
208             omitNamespaces != null && !omitNamespaces.Contains(Namespace))
209        sb.Append(Namespace).Append('.');
210      if (GenericArgCounts != null) {
211        sb.Append(string.Join(".", GetNestedClassesInCode(omitNamespaces, includeNamespaces)));
212      } else {
213        sb.Append(ClassName);
214        if (IsGeneric) {
215          sb.Append("<");
216          sb.Append(
217            string.Join(", ",
218                        GenericArgs
219                          .Select(a => a.GetTypeNameInCode(omitNamespaces, includeNamespaces))
220                          .ToArray()));
221          sb.Append(">");
222        }
223      }
224      sb.Append(MemoryMagic);
225      return sb.ToString();
226    }
227
228    public string GetTypeNameInCode(HashSet<string> omitNamespaces) {
229      return GetTypeNameInCode(omitNamespaces, false);
230    }
231
232    public string GetTypeNameInCode(bool includeNamespaces) {
233      return GetTypeNameInCode(null, includeNamespaces);
234    }
235
236
237    /// <summary>
238    /// Returns a <see cref="System.String"/> that represents this instance.
239    /// </summary>
240    /// <returns>
241    /// A <see cref="System.String"/> that represents this instance.
242    /// </returns>
243    public override string ToString() {
244      return ToString(true);
245    }
246
247
248    /// <summary>
249    /// Lexicographically compare version information and make sure type and assembly
250    /// names are identical. This function recursively checks generic type arguments.
251    /// </summary>
252    /// <param name="typeName">Name of the type.</param>
253    /// <returns>
254    ///   <c>true</c> if is newer than the specified type name; otherwise, <c>false</c>.
255    /// </returns>
256    public bool IsNewerThan(TypeName typeName) {
257      try {
258        if (this.ClassName != typeName.ClassName ||
259          this.Namespace != typeName.Namespace ||
260          this.AssemblyName != typeName.AssemblyName)
261          throw new Exception("Cannot compare versions of different types");
262        if (CompareVersions(
263          this.AssemblyAttribues["Version"],
264          typeName.AssemblyAttribues["Version"]) > 0)
265          return true;
266        IEnumerator<TypeName> thisIt = this.GenericArgs.GetEnumerator();
267        IEnumerator<TypeName> tIt = typeName.GenericArgs.GetEnumerator();
268        while (thisIt.MoveNext()) {
269          tIt.MoveNext();
270          if (thisIt.Current.IsNewerThan(tIt.Current))
271            return true;
272        }
273        return false;
274      } catch (KeyNotFoundException) {
275        throw new Exception("Could not extract version information from type string");
276      }
277    }
278
279
280    /// <summary>
281    /// Make sure major and minor version number are identical. This function
282    /// recursively checks generic type arguments.
283    /// </summary>
284    /// <param name="typeName">Name of the type.</param>
285    /// <returns>
286    ///   <c>true</c> if the specified type names are compatible; otherwise, <c>false</c>.
287    /// </returns>
288    public bool IsCompatible(TypeName typeName) {
289      try {
290        if (this.ClassName != typeName.ClassName ||
291          this.Namespace != typeName.Namespace ||
292          this.AssemblyName != typeName.AssemblyName)
293          throw new Exception("Cannot compare versions of different types");
294        Version thisVersion = new Version(this.AssemblyAttribues["Version"]);
295        Version tVersion = new Version(typeName.AssemblyAttribues["Version"]);
296        if (this.AssemblyName == "mscorlib" &&
297          (thisVersion.Major == 2 || thisVersion.Major == 4) &&
298          (tVersion.Major == 2 || tVersion.Major == 4)) {
299          // skip version check
300        } else if (thisVersion.Major != tVersion.Major ||
301                   thisVersion.Minor != tVersion.Minor)
302          return false;
303        IEnumerator<TypeName> thisIt = this.GenericArgs.GetEnumerator();
304        IEnumerator<TypeName> tIt = typeName.GenericArgs.GetEnumerator();
305        while (thisIt.MoveNext()) {
306          tIt.MoveNext();
307          if (!thisIt.Current.IsCompatible(tIt.Current))
308            return false;
309        }
310        return true;
311      } catch (KeyNotFoundException) {
312        throw new Exception("Could not extract version infomration from type string");
313      }
314    }
315
316    private static int CompareVersions(string v1string, string v2string) {
317      return new Version(v1string).CompareTo(new Version(v2string));
318    }
319  }
320}
Note: See TracBrowser for help on using the repository browser.