Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
05/11/09 13:35:32 (16 years ago)
Author:
epitzer
Message:

Better type name parser. Replace reflection based type name generation, better exceptions during deserialization. (#613)

Location:
trunk/sources/HeuristicLab.Persistence
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Persistence/3.3/Auxiliary/TypeExtensions.cs

    r1703 r1779  
    77
    88    public static string VersionInvariantName(this Type type) {
    9       StringBuilder sb = new StringBuilder();
    10       TypeStringBuilder.BuildVersionInvariantName(type, sb);
    11       return sb.ToString();
     9      return TypeNameParser.Parse(type.AssemblyQualifiedName).ToString(false);
    1210    }
    1311
  • trunk/sources/HeuristicLab.Persistence/3.3/Auxiliary/TypeStringBuilder.cs

    r1776 r1779  
    4040          {"&", "AMPERSAND"},
    4141          {".", "DOT"},
     42          {"-", "DASH"},
    4243          {"+", "PLUS"},
    4344          {",", "COMMA"},
     
    4950          {"`", "BACKTICK"} };
    5051      private static Regex NumberRegex = new Regex("^\\d+$");
    51       private static Regex TokenRegex = new Regex("[&.+,\\[\\]* =`]|\\d+|[a-zA-Z][a-zA-Z0-9]*");
     52      private static Regex TokenRegex = new Regex("[-&.+,\\[\\]* =`]|\\d+|[a-zA-Z][a-zA-Z0-9]*");
    5253      public string Name { get; private set; }
    5354      public string Value { get; private set; }
    5455      public int? Number { get; private set; }
    55       private Token(string value) {
     56      public int Position { get; private set; }
     57      private Token(string value, int pos) {
     58        Position = pos;
    5659        if (tokens.ContainsKey(value)) {
    5760          Name = tokens[value];
     
    6366      }
    6467      public static IEnumerable<Token> Tokenize(string s) {
     68        int pos = 0;
    6569        foreach (Match m in TokenRegex.Matches(s)) {
    66           yield return new Token(m.Value);
     70          yield return new Token(m.Value, pos);
     71          pos += m.Length;
    6772        }
    6873      }
     
    7883    }
    7984
    80     Queue<Token> tokens;
     85    private Queue<Token> tokens;
     86    private int Position {
     87      get {
     88        if (tokens.Count == 0)
     89          return -1;
     90        else
     91          return tokens.Peek().Position;
     92      }
     93    }
    8194
    8295    private TypeNameParser(string s) {
     
    8497    }
    8598
    86     public static string StripVersion(string s) {
     99    public static TypeName Parse(string s) {
    87100      TypeNameParser p = new TypeNameParser(s);
    88       return p.TransformTypeSpec();
    89     }
    90 
    91 
    92     private string TransformTypeSpec() {
    93       string result = TransformSimpleTypeSpec();
    94       if (ConsumeToken("AMPERSAND")) {
    95         return result + "&";
    96       } else {
    97         return result;
    98       }
    99     }
    100 
    101     private string TransformSimpleTypeSpec() {
     101      try {
     102        return p.TransformTypeSpec();
     103      } catch (ParseError x) {
     104        if (p.Position > 0)
     105          throw new ParseError(String.Format(
     106            "Could not parse typename: {0}\n\"{1}====>{2}<===={3}",
     107            x.Message,
     108            s.Substring(0, p.Position),
     109            s[p.Position],
     110            s.Substring(p.Position, s.Length - p.Position)));
     111        else
     112          throw new ParseError(String.Format(
     113            "Could not parse typenname \"{0}\" at end of input: {1}",
     114            s,
     115            x.Message));
     116      }
     117    }
     118
     119    private TypeName TransformTypeSpec() {
     120      TypeName t = TransformSimpleTypeSpec();
     121      t.IsReference = ConsumeToken("AMPERSAND");
     122      return t;
     123    }
     124
     125    private TypeName TransformSimpleTypeSpec() {
    102126      List<string> nameSpace = new List<string>();
    103127      nameSpace.Add(ConsumeIdentifier());
    104128      while (ConsumeToken("DOT"))
    105129        nameSpace.Add(ConsumeIdentifier());
    106       List<string> typeName = new List<string>();
     130      List<string> className = new List<string>();
    107131      if (nameSpace.Count > 0) {
    108         typeName.Add(nameSpace[nameSpace.Count - 1]);
     132        className.Add(nameSpace[nameSpace.Count - 1]);
    109133        nameSpace.RemoveAt(nameSpace.Count - 1);
    110134      }
    111135      while (ConsumeToken("PLUS"))
    112         typeName.Add(ConsumeIdentifier());
    113       string genericString = "";
     136        className.Add(ConsumeIdentifier());
     137      TypeName typeName = new TypeName(
     138        string.Join(".", nameSpace.ToArray()),
     139        string.Join("+", className.ToArray()));
    114140      if (ConsumeToken("BACKTICK")) {
    115         string number = ConsumeNumber().ToString();
    116         ConsumeToken("OPEN_BRACKET", true);
    117         string generics = TransformGenerics();
    118         ConsumeToken("CLOSE_BRACKET", true);
    119         genericString = "`" + number + "[" + generics + "]";
     141        int nGenericArgs = ConsumeNumber();
     142        if (ConsumeToken("OPEN_BRACKET") &&
     143          CanConsumeToken("OPEN_BRACKET")) {
     144          typeName.GenericArgs.AddRange(TransformGenerics());
     145          ConsumeToken("CLOSE_BRACKET", true);
     146        }
    120147      }
    121148      StringBuilder pointerOrArray = new StringBuilder();
     
    124151          pointerOrArray.Append("*");
    125152        } else if (ConsumeToken("OPEN_BRACKET")) {
     153          pointerOrArray.Append('[');
    126154          ParseDimension(pointerOrArray);
    127155          while (ConsumeToken("COMMA")) {
     
    130158          }
    131159          ConsumeToken("CLOSE_BRACKET", true);
     160          pointerOrArray.Append(']');
    132161        } else {
    133162          break;
    134163        }
    135164      }
    136       string assembly = "";
     165      typeName.MemoryMagic = pointerOrArray.ToString();
    137166      if (ConsumeComma()) {
    138         assembly = ConsumeIdentifier();
     167        StringBuilder sb = new StringBuilder();
     168        sb.Append(ConsumeIdentifier());
     169        while (CanConsumeToken("DOT") ||
     170          CanConsumeToken("DASH") ||
     171          CanConsumeNumber() ||
     172          CanConsumeIdentifier()) {
     173          if (ConsumeToken("DOT"))
     174            sb.Append('.');
     175          else if (ConsumeToken("DASH"))
     176            sb.Append('-');
     177          else if (CanConsumeNumber())
     178            sb.Append(ConsumeNumber());
     179          else
     180            sb.Append(ConsumeIdentifier());
     181        }
     182        typeName.AssemblyName = sb.ToString();
    139183        while (ConsumeComma()) {
    140           TransformAssemblyProperty();
    141         }
    142       }
    143       return string.Join(".", nameSpace.ToArray()) + "." +
    144         string.Join("+", typeName.ToArray()) +
    145         genericString +
    146         pointerOrArray.ToString() +
    147         ", " +
    148         assembly;
     184          KeyValuePair<string, string> property =
     185            TransformAssemblyProperty();
     186          typeName.AssemblyAttribues.Add(property.Key, property.Value);
     187        }
     188      }
     189      return typeName;
    149190    }
    150191
     
    164205    }
    165206
    166     private string TransformGenerics() {
     207    private IEnumerable<TypeName> TransformGenerics() {
    167208      ConsumeToken("OPEN_BRACKET", true);
    168       List<string> typenames = new List<string>();
    169       typenames.Add(TransformSimpleTypeSpec());
     209      yield return TransformSimpleTypeSpec();
    170210      ConsumeToken("CLOSE_BRACKET", true);
    171211      while (ConsumeToken("COMMA")) {
    172212        ConsumeToken("OPEN_BRACKET", true);
    173         typenames.Add(TransformSimpleTypeSpec());
     213        yield return TransformSimpleTypeSpec();
    174214        ConsumeToken("CLOSE_BRACKET", true);
    175215      }
    176       return "[" + string.Join("],[", typenames.ToArray()) + "]";
    177     }
    178 
    179     private string TransformAssemblyProperty() {
     216    }
     217
     218    private KeyValuePair<string, string> TransformAssemblyProperty() {
    180219      if (ConsumeIdentifier("Version")) {
    181220        ConsumeToken("EQUALS", true);
    182         TransformVersion();
     221        return new KeyValuePair<string, string>(
     222          "Version",
     223          TransformVersion());
    183224      } else if (ConsumeIdentifier("PublicKey")) {
    184225        ConsumeToken("EQUALS", true);
    185         ConsumeIdentifier();
     226        return new KeyValuePair<string, string>(
     227          "PublicKey",
     228          ConsumeIdentifier());
    186229      } else if (ConsumeIdentifier("PublicKeyToken")) {
    187230        ConsumeToken("EQUALS", true);
    188         ConsumeIdentifier();
     231        return new KeyValuePair<string, string>(
     232          "PublicKeyToken",
     233          ConsumeIdentifier());
    189234      } else if (ConsumeIdentifier("Culture")) {
    190235        ConsumeToken("EQUALS", true);
    191         ConsumeIdentifier();
     236        return new KeyValuePair<string, string>(
     237          "Culture",
     238          ConsumeIdentifier());
    192239      } else if (ConsumeIdentifier("Custom")) {
    193240        ConsumeToken("EQUALS", true);
    194         ConsumeIdentifier();
     241        return new KeyValuePair<string, string>(
     242          "Custom",
     243          ConsumeIdentifier());
    195244      } else {
    196245        throw new ParseError(String.Format(
     
    198247          tokens.Peek().ToString()));
    199248      }
    200       return "";
    201249    }
    202250    private string TransformVersion() {
    203       ConsumeNumber();
     251      StringBuilder version = new StringBuilder();
     252      version.Append(ConsumeNumber());
    204253      ConsumeToken("DOT");
    205       ConsumeNumber();
     254      version.Append('.').Append(ConsumeNumber());
    206255      ConsumeToken("DOT");
    207       ConsumeNumber();
     256      version.Append('.').Append(ConsumeNumber());
    208257      ConsumeToken("DOT");
    209       ConsumeNumber();
    210       return "";
     258      version.Append('.').Append(ConsumeNumber());
     259      return version.ToString();
    211260    }
    212261
     
    238287    }
    239288
     289    private bool CanConsumeIdentifier() {
     290      return tokens.Count > 0 && tokens.Peek().Value != null;
     291    }
     292
    240293    private string ConsumeIdentifier() {
    241294      if (tokens.Count == 0)
     
    259312    private bool ConsumeToken(string name) {
    260313      return ConsumeToken(name, false);
     314    }
     315
     316    private bool CanConsumeToken(string name) {
     317      if (tokens.Count == 0)
     318        return false;
     319      if (tokens.Peek().Name == name)
     320        return true;
     321      return false;
    261322    }
    262323
     
    282343    }
    283344
     345
    284346  }
    285347
    286348  public class TypeName {
    287     public bool IsReference { get; private set; }
    288     public bool IsArray { get { return Dimension.Length > 0; } }
    289     public bool IsPointer { get; private set; }
     349    public string Namespace { get; private set; }
     350    public string ClassName { get; private set; }
     351    public List<TypeName> GenericArgs { get; internal set; }
    290352    public bool IsGeneric { get { return GenericArgs.Count > 0; } }
    291     public List<TypeName> GenericArgs { get; private set; }
    292     public string Dimension { get; private set; }
    293     public string ClassName { get; private set; }
    294     public string Namespace { get; private set; }
    295     public string AssemblyNmae { get; private set; }
    296     public string AssemblyAttribues { get; private set; }
    297     public TypeName(string typeName) {
     353    public string MemoryMagic { get; internal set; }
     354    public string AssemblyName { get; internal set; }
     355    public Dictionary<string, string> AssemblyAttribues { get; internal set; }
     356    public bool IsReference { get; internal set; }
     357
     358    internal TypeName(string nameSpace, string className) {
     359      Namespace = nameSpace;
     360      ClassName = className;
     361      GenericArgs = new List<TypeName>();
     362      MemoryMagic = "";
     363      AssemblyAttribues = new Dictionary<string, string>();
     364    }
     365
     366    public string ToString(bool full) {
     367      StringBuilder sb = new StringBuilder();
     368      sb.Append(Namespace).Append('.').Append(ClassName);
     369      if (IsGeneric) {
     370        sb.Append('`').Append(GenericArgs.Count).Append('[');
     371        bool first = true;
     372        foreach (TypeName t in GenericArgs) {
     373          if (first)
     374            first = false;
     375          else
     376            sb.Append(',');
     377          sb.Append('[').Append(t.ToString(full)).Append(']');
     378        }
     379        sb.Append(']');
     380      }
     381      sb.Append(MemoryMagic);
     382      if (AssemblyName != null)
     383        sb.Append(", ").Append(AssemblyName);
     384      if (full)
     385        foreach (var property in AssemblyAttribues)
     386          sb.Append(", ").Append(property.Key).Append('=').Append(property.Value);
     387      return sb.ToString();
     388    }
     389
     390    public override string ToString() {
     391      return ToString(true);
     392    }
     393
     394    public bool IsOlderThan(TypeName t) {
     395      if (this.ClassName != t.ClassName ||
     396        this.Namespace != t.Namespace ||
     397        this.AssemblyName != t.AssemblyName)
     398        throw new Exception("Cannot compare versions of different types");
     399      if (CompareVersions(
     400        this.AssemblyAttribues["Version"],
     401        t.AssemblyAttribues["Version"]) < 0)
     402        return true;
     403      IEnumerator<TypeName> thisIt = this.GenericArgs.GetEnumerator();
     404      IEnumerator<TypeName> tIt = t.GenericArgs.GetEnumerator();
     405      while (thisIt.MoveNext()) {
     406        tIt.MoveNext();
     407        if (thisIt.Current.IsOlderThan(tIt.Current))
     408          return true;
     409      }
     410      return false;
     411    }
     412
     413    private static int CompareVersions(string v1string, string v2string) {
     414      return new Version(v1string).CompareTo(new Version(v2string));
    298415    }
    299416  }
    300 
    301   public static class TypeStringBuilder {
    302 
    303     internal static void BuildDeclaringTypeChain(Type type, StringBuilder sb) {
    304       if (type.DeclaringType != null) {
    305         BuildDeclaringTypeChain(type.DeclaringType, sb);
    306         sb.Append(type.DeclaringType.Name).Append('+');
    307       }
    308     }
    309 
    310     internal static void BuildVersionInvariantName(Type type, StringBuilder sb) {
    311       sb.Append(type.Namespace).Append('.');
    312       BuildDeclaringTypeChain(type, sb);
    313       sb.Append(type.Name);
    314       if (type.IsGenericType) {
    315         sb.Append("[");
    316         Type[] args = type.GetGenericArguments();
    317         for (int i = 0; i < args.Length; i++) {
    318           sb.Append("[");
    319           BuildVersionInvariantName(args[i], sb);
    320           sb.Append("],");
    321         }
    322         if (args.Length > 0)
    323           sb.Remove(sb.Length - 1, 1);
    324         sb.Append("]");
    325       }
    326       sb.Append(", ").Append(type.Assembly.GetName().Name);
    327     }
    328 
    329     public static string StripVersion(string typename) {
    330       return TypeNameParser.StripVersion(typename);
    331     }
    332 
    333   }
    334 
    335417}
  • trunk/sources/HeuristicLab.Persistence/3.3/Core/DeSerializer.cs

    r1703 r1779  
    7474          try {
    7575            type = Type.GetType(typeMapping.TypeName, true);
    76           } catch (Exception e) {
     76          } catch (Exception) {
    7777            Logger.Error(String.Format(
    7878              "Cannot load type \"{0}\", falling back to loading with partial name", typeMapping.TypeName));
    7979            string[] typeNameParts = typeMapping.TypeName.Split(new[] { ',' });
    80             Assembly a = Assembly.LoadWithPartialName(typeNameParts[typeNameParts.Length - 1].Trim());
    81             Array.Resize(ref typeNameParts, typeNameParts.Length - 1);
    82             type = a.GetType(string.Join(",", typeNameParts), true);
     80            try {
     81              Assembly a = Assembly.LoadWithPartialName(typeNameParts[typeNameParts.Length - 1].Trim());
     82              Array.Resize(ref typeNameParts, typeNameParts.Length - 1);
     83              type = a.GetType(string.Join(",", typeNameParts), true);
     84            } catch (Exception) {
     85              throw new PersistenceException(String.Format(
     86                "Could not load type \"{0}\"",
     87                typeMapping.TypeName));
     88            }
    8389          }
    8490          typeIds.Add(typeMapping.Id, type);
     
    8793        }
    8894        return map;
     95      } catch (PersistenceException) {
     96        throw;
    8997      } catch (Exception e) {
    9098        throw new PersistenceException(
  • trunk/sources/HeuristicLab.Persistence/3.3/Default/Xml/XmlParser.cs

    r1734 r1779  
    131131
    132132    private static object Deserialize(ZipFile zipFile) {
    133       try {       
     133      try {
    134134        Deserializer deSerializer = new Deserializer(
    135135          ParseTypeCache(
  • trunk/sources/HeuristicLab.Persistence/UnitTests/UseCases.cs

    r1776 r1779  
    525525    [TestMethod]
    526526    public void TestTypeStringConversion() {
    527       string version = TypeStringBuilder.StripVersion(typeof(List<int>[]).AssemblyQualifiedName);
    528       Assert.AreEqual(version, typeof(List<int>[]).VersionInvariantName());
     527      string name = typeof(List<int>[]).AssemblyQualifiedName;
     528      string shortName =
     529        "System.Collections.Generic.List`1[[System.Int32, mscorlib]][], mscorlib";
     530      Assert.AreEqual(name, TypeNameParser.Parse(name).ToString());       
     531      Assert.AreEqual(shortName, TypeNameParser.Parse(name).ToString(false));
     532      Assert.AreEqual(shortName, typeof(List<int>[]).VersionInvariantName());
    529533    }
    530534
Note: See TracChangeset for help on using the changeset viewer.