source: branches/2520_PersistenceReintegration/HeuristicLab.Persistence/3.3/Auxiliary/TypeName.cs @ 16453

Last change on this file since 16453 was 16453, checked in by jkarder, 8 months ago

#2520: updated year of copyrights

File size: 11.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2019 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.Default.CompositeSerializers.Storable;
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  [StorableClass]
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        }
193        else {
194          yield return string.Format("{0}<{1}>",
195            pair.n,
196            string.Join(",",
197              GenericArgs
198                .GetRange(i, pair.c)
199                .Select(a => a.GetTypeNameInCode(omitNamespaces, includeAllNamespaces))));
200          i += pair.c;
201        }
202      }
203    }
204
205    private string GetTypeNameInCode(HashSet<string> omitNamespaces, bool includeNamespaces) {
206      var sb = new StringBuilder();
207      if (!string.IsNullOrEmpty(Namespace) &&
208            (omitNamespaces == null && includeNamespaces) ||
209             omitNamespaces != null && !omitNamespaces.Contains(Namespace))
210          sb.Append(Namespace).Append('.');
211      if (GenericArgCounts != null) {
212        sb.Append(string.Join(".", GetNestedClassesInCode(omitNamespaces, includeNamespaces)));
213      } else {
214        sb.Append(ClassName);
215        if (IsGeneric) {
216          sb.Append("<");
217          sb.Append(
218            string.Join(", ",
219                        GenericArgs
220                          .Select(a => a.GetTypeNameInCode(omitNamespaces, includeNamespaces))
221                          .ToArray()));
222          sb.Append(">");
223        }
224      }
225      sb.Append(MemoryMagic);
226      return sb.ToString();
227    }
228
229    public string GetTypeNameInCode(HashSet<string> omitNamespaces) {
230      return GetTypeNameInCode(omitNamespaces, false);
231    }
232
233    public string GetTypeNameInCode(bool includeNamespaces) {
234      return GetTypeNameInCode(null, includeNamespaces);
235    }
236
237
238    /// <summary>
239    /// Returns a <see cref="System.String"/> that represents this instance.
240    /// </summary>
241    /// <returns>
242    /// A <see cref="System.String"/> that represents this instance.
243    /// </returns>
244    public override string ToString() {
245      return ToString(true);
246    }
247
248
249    /// <summary>
250    /// Lexicographically compare version information and make sure type and assembly
251    /// names are identical. This function recursively checks generic type arguments.
252    /// </summary>
253    /// <param name="typeName">Name of the type.</param>
254    /// <returns>
255    ///   <c>true</c> if is newer than the specified type name; otherwise, <c>false</c>.
256    /// </returns>
257    public bool IsNewerThan(TypeName typeName) {
258      try {
259        if (this.ClassName != typeName.ClassName ||
260          this.Namespace != typeName.Namespace ||
261          this.AssemblyName != typeName.AssemblyName)
262          throw new Exception("Cannot compare versions of different types");
263        if (CompareVersions(
264          this.AssemblyAttribues["Version"],
265          typeName.AssemblyAttribues["Version"]) > 0)
266          return true;
267        IEnumerator<TypeName> thisIt = this.GenericArgs.GetEnumerator();
268        IEnumerator<TypeName> tIt = typeName.GenericArgs.GetEnumerator();
269        while (thisIt.MoveNext()) {
270          tIt.MoveNext();
271          if (thisIt.Current.IsNewerThan(tIt.Current))
272            return true;
273        }
274        return false;
275      }
276      catch (KeyNotFoundException) {
277        throw new Exception("Could not extract version information from type string");
278      }
279    }
280
281
282    /// <summary>
283    /// Make sure major and minor version number are identical. This function
284    /// recursively checks generic type arguments.
285    /// </summary>
286    /// <param name="typeName">Name of the type.</param>
287    /// <returns>
288    ///   <c>true</c> if the specified type names are compatible; otherwise, <c>false</c>.
289    /// </returns>
290    public bool IsCompatible(TypeName typeName) {
291      try {
292        if (this.ClassName != typeName.ClassName ||
293          this.Namespace != typeName.Namespace ||
294          this.AssemblyName != typeName.AssemblyName)
295          throw new Exception("Cannot compare versions of different types");
296        Version thisVersion = new Version(this.AssemblyAttribues["Version"]);
297        Version tVersion = new Version(typeName.AssemblyAttribues["Version"]);
298        if (this.AssemblyName == "mscorlib" &&
299          (thisVersion.Major == 2 || thisVersion.Major == 4) &&
300          (tVersion.Major == 2 || tVersion.Major == 4)) {
301          // skip version check
302        } else if (thisVersion.Major != tVersion.Major ||
303                   thisVersion.Minor != tVersion.Minor)
304          return false;
305        IEnumerator<TypeName> thisIt = this.GenericArgs.GetEnumerator();
306        IEnumerator<TypeName> tIt = typeName.GenericArgs.GetEnumerator();
307        while (thisIt.MoveNext()) {
308          tIt.MoveNext();
309          if (!thisIt.Current.IsCompatible(tIt.Current))
310            return false;
311        }
312        return true;
313      }
314      catch (KeyNotFoundException) {
315        throw new Exception("Could not extract version infomration from type string");
316      }
317    }
318
319    private static int CompareVersions(string v1string, string v2string) {
320      return new Version(v1string).CompareTo(new Version(v2string));
321    }
322  }
323}
Note: See TracBrowser for help on using the repository browser.