Free cookie consent management tool by TermsFeed Policy Generator

source: branches/RemoveBackwardsCompatibility/HeuristicLab.Persistence/3.3/Auxiliary/TypeLoader.cs

Last change on this file was 12012, checked in by ascheibe, 10 years ago

#2212 merged r12008, r12009, r12010 back into trunk

File size: 8.1 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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.Reflection;
25using HeuristicLab.Persistence.Core;
26using HeuristicLab.Tracing;
27
28namespace HeuristicLab.Persistence.Auxiliary {
29  internal class TypeLoader {
30    #region Mono Compatibility
31    private static TypeName cachedMonoRuntimeType;
32    private static TypeName cachedWindowsRuntimeType;
33    private static TypeName cachedMonoObjectEqualityComparerType;
34    private static TypeName cachedWindowsObjectEqualityComparerType;
35
36    private static bool MonoInstalled {
37      get { return Type.GetType("Mono.Runtime") != null; }
38    }
39
40    static TypeLoader() {
41      // we use Int32 here because we get all the information about Mono's mscorlib and just have to change the class name
42      cachedMonoRuntimeType = TypeNameParser.Parse(typeof(System.Int32).AssemblyQualifiedName);
43      cachedMonoRuntimeType = new TypeName(cachedMonoRuntimeType, "MonoType");
44
45      cachedWindowsRuntimeType = TypeNameParser.Parse(typeof(System.Int32).AssemblyQualifiedName);
46      cachedWindowsRuntimeType = new TypeName(cachedWindowsRuntimeType, "RuntimeType");
47
48      // we need the information about the Persistence assembly, so we use TypeName here because it is contained in this assembly
49      cachedMonoObjectEqualityComparerType = TypeNameParser.Parse(typeof(TypeName).AssemblyQualifiedName);
50      cachedMonoObjectEqualityComparerType = new TypeName(cachedMonoObjectEqualityComparerType, "ObjectEqualityComparer", "HeuristicLab.Persistence.Mono");
51
52      cachedWindowsObjectEqualityComparerType = TypeNameParser.Parse(typeof(System.Int32).AssemblyQualifiedName);
53      cachedWindowsObjectEqualityComparerType = new TypeName(cachedWindowsObjectEqualityComparerType, "ObjectEqualityComparer", "System.Collections.Generic");
54    }
55    #endregion
56
57    public static Type Load(string typeNameString) {
58      TypeName typeName = null;
59      try {
60        typeName = TypeNameParser.Parse(typeNameString);
61      }
62      catch (Exception) {
63        throw new PersistenceException(String.Format(
64           "Could not parse type string \"{0}\"",
65           typeNameString));
66      }
67
68      try {
69        // try to load type normally
70        return LoadInternal(typeName);
71      }
72      catch (PersistenceException) {
73        #region Mono Compatibility
74        // if that fails, try to convert to the corresponding Mono or .NET type
75        if (MonoInstalled) {
76          typeName = GetMonoType(typeName);
77          Logger.Info(String.Format(@"Trying to load Mono type ""{0}"" instead of .NET type ""{1}""",
78                                    typeName, typeNameString));
79        } else {
80          typeName = GetDotNetType(typeName);
81          Logger.Info(String.Format(@"Trying to load .NET type ""{0}"" instead of Mono type ""{1}""",
82                                    typeName, typeNameString));
83
84        }
85        return LoadInternal(typeName);
86        #endregion
87      }
88    }
89
90    private static Type LoadInternal(TypeName typeName) {
91      Type type;
92      try {
93        type = Type.GetType(typeName.ToString(true, true), true);
94      }
95      catch (Exception) {
96        Logger.Warn(String.Format(
97          "Cannot load type \"{0}\", falling back to partial name", typeName.ToString(true, true)));
98        type = LoadWithPartialName(typeName);
99        CheckCompatibility(typeName, type);
100      }
101      return type;
102    }
103
104    private static Type LoadWithPartialName(TypeName typeName) {
105      try {
106#pragma warning disable 0618
107        Assembly a = Assembly.LoadWithPartialName(typeName.AssemblyName);
108        // the suggested Assembly.Load() method fails to load assemblies outside the GAC
109#pragma warning restore 0618
110        return a.GetType(typeName.ToString(false, false), true);
111      }
112      catch (Exception) {
113        throw new PersistenceException(String.Format(
114          "Could not load type \"{0}\"",
115          typeName.ToString(true, true)));
116      }
117    }
118
119    private static void CheckCompatibility(TypeName typeName, Type type) {
120      try {
121        TypeName loadedTypeName = TypeNameParser.Parse(type.AssemblyQualifiedName);
122        if (!typeName.IsCompatible(loadedTypeName))
123          throw new PersistenceException(String.Format(
124            "Serialized type is incompatible with available type: serialized: {0}, loaded: {1}",
125            typeName.ToString(true, true),
126            type.AssemblyQualifiedName));
127        if (typeName.IsNewerThan(loadedTypeName))
128          throw new PersistenceException(String.Format(
129            "Serialized type is newer than available type: serialized: {0}, loaded: {1}",
130            typeName.ToString(true, true),
131            type.AssemblyQualifiedName));
132      }
133      catch (PersistenceException) {
134        throw;
135      }
136      catch (Exception e) {
137        Logger.Warn(String.Format(
138          "Could not perform version check requested type was {0} while loaded type is {1}:",
139          typeName.ToString(true, true),
140          type.AssemblyQualifiedName),
141                    e);
142      }
143    }
144
145    #region Mono Compatibility
146    /// <summary>
147    /// Returns the corresponding type for the Mono runtime
148    /// </summary>
149    /// <returns>
150    /// The remapped typeName, or the original typeName if no mapping was found
151    /// </returns>
152    private static TypeName GetMonoType(TypeName typeName) {
153      // map System.RuntimeType to System.MonoType
154      if (typeName.Namespace == "System" && typeName.ClassName == "RuntimeType") {
155        return cachedMonoRuntimeType;
156        // map System.Collections.Generic.ObjectEqualityComparer to HeuristicLab.Mono.ObjectEqualityComparer
157      } else if (typeName.Namespace == "System.Collections.Generic" && typeName.ClassName == "ObjectEqualityComparer") {
158        TypeName newTypeName = new TypeName(cachedMonoObjectEqualityComparerType);
159        newTypeName.GenericArgs = new List<TypeName>(typeName.GenericArgs);
160        return newTypeName;
161      }
162      return typeName;
163    }
164
165    /// <summary>
166    /// Returns the corresponding type for the .NET runtime
167    /// </summary>
168    /// <returns>
169    /// The remapped typeName, or the original typeName if no mapping was found
170    /// </returns>
171    private static TypeName GetDotNetType(TypeName typeName) {
172      // map System.MonoType to System.RuntimeType
173      if (typeName.Namespace == "System" && typeName.ClassName == "MonoType") {
174        return cachedWindowsRuntimeType;
175        // maps Mono's string comparer to System.Collections.Generic.ObjectEqualityComparer<string>
176      } else if (typeName.Namespace == "System.Collections.Generic" && typeName.ClassName == "InternalStringComparer") {
177        TypeName newTypeName = new TypeName(cachedWindowsObjectEqualityComparerType);
178        var genericArgsList = new List<TypeName>();
179        genericArgsList.Add(new TypeName(typeof(String).Namespace, "String"));
180        newTypeName.GenericArgs = genericArgsList;
181        return newTypeName;
182      } else if (typeName.Namespace == "System.Collections.Generic" && typeName.ClassName == "EqualityComparer+DefaultComparer") {
183        TypeName newTypeName = new TypeName(cachedWindowsObjectEqualityComparerType);
184        newTypeName.GenericArgs = new List<TypeName>(typeName.GenericArgs);
185        return newTypeName;
186      }
187      return typeName;
188    }
189    #endregion
190  }
191}
Note: See TracBrowser for help on using the repository browser.