Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
01/20/17 11:16:42 (8 years ago)
Author:
jkarder
Message:

#2520: worked on persistence

Location:
branches/PersistenceOverhaul/HeuristicLab.Persistence/4.0
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/PersistenceOverhaul/HeuristicLab.Persistence/4.0/Core/Mapper.cs

    r14549 r14594  
    139139      bundle.RootBoxId = mapper.GetBoxId(o);
    140140      bundle.AddRangeTransformerGuids(mapper.transformers.GetValues().Select(x => x.Guid).Select(x => ByteString.CopyFrom(x.ToByteArray())));
    141       bundle.AddRangeTypeGuids(mapper.types.GetValues().Select(x => StaticCache.GetGuid(x)).Select(x => ByteString.CopyFromUtf8(x)));
     141      bundle.AddRangeTypeGuids(mapper.types.GetValues().Select(x => x.AssemblyQualifiedName ?? x.Name).Select(x => ByteString.CopyFromUtf8(x)));
    142142      bundle.AddRangeStrings(mapper.strings.GetValues());
    143143      bundle.AddRangeBoxes(mapper.boxId2Box.OrderBy(x => x.Key).Select(x => x.Value));
     
    146146    public static object ToObject(Bundle bundle) {
    147147      var mapper = new Mapper();
    148       mapper.types = new Index<Type>(bundle.TypeGuidsList.Select(x => x.ToStringUtf8()).Select(x => StaticCache.GetType(x)));
     148      mapper.types = new Index<Type>(bundle.TypeGuidsList.Select(x => x.ToStringUtf8()).Select(x => Type.GetType(x)));
    149149      mapper.strings = new Index<string>(bundle.StringsList);
    150150      mapper.boxId2Box = bundle.BoxesList.Select((b, i) => new { Box = b, Index = i }).ToDictionary(k => (uint)k.Index + 1, v => v.Box);
  • branches/PersistenceOverhaul/HeuristicLab.Persistence/4.0/Core/StaticCache.cs

    r14549 r14594  
    3535    private Dictionary<Guid, ITransformer> guid2Transformer;
    3636    private Dictionary<ITransformer, Guid> transformer2Guid;
    37     private Dictionary<string, Type> guid2Type;
    38     private Dictionary<Type, string> type2Guid;
     37    //private Dictionary<string, Type> guid2Type;
     38    //private Dictionary<Type, string> type2Guid;
    3939    private Dictionary<Type, TypeInfo> typeInfos;
    4040    private ExtensionRegistry extensionRegistry;
     
    4343      guid2Transformer = new Dictionary<Guid, ITransformer>();
    4444      transformer2Guid = new Dictionary<ITransformer, Guid>();
    45       guid2Type = new Dictionary<string, Type>();
    46       type2Guid = new Dictionary<Type, string>();
     45      //guid2Type = new Dictionary<string, Type>();
     46      //type2Guid = new Dictionary<Type, string>();
    4747      typeInfos = new Dictionary<Type, TypeInfo>();
    4848      extensionRegistry = ExtensionRegistry.CreateInstance();
     
    104104      //       RegisterType(new Guid("E92C35AD-32B1-4F37-B8D2-BE2F5FEB465B"), typeof(Dictionary<,>));
    105105
    106       RegisterTypeAndFullName(typeof(object));
    107       RegisterTypeAndFullName(typeof(bool));
    108       RegisterTypeAndFullName(typeof(byte));
    109       RegisterTypeAndFullName(typeof(sbyte));
    110       RegisterTypeAndFullName(typeof(short));
    111       RegisterTypeAndFullName(typeof(ushort));
    112       RegisterTypeAndFullName(typeof(char));
    113       RegisterTypeAndFullName(typeof(int));
    114       RegisterTypeAndFullName(typeof(uint));
    115       RegisterTypeAndFullName(typeof(long));
    116       RegisterTypeAndFullName(typeof(ulong));
    117       RegisterTypeAndFullName(typeof(float));
    118       RegisterTypeAndFullName(typeof(double));
    119       RegisterTypeAndFullName(typeof(decimal));
    120       RegisterTypeAndFullName(typeof(DateTime));
    121       RegisterTypeAndFullName(typeof(TimeSpan));
    122       RegisterTypeAndFullName(typeof(Font));
    123       RegisterTypeAndFullName(typeof(Color));
    124       RegisterTypeAndFullName(typeof(Bitmap));
    125       RegisterTypeAndFullName(typeof(Point));
    126       RegisterTypeAndFullName(typeof(KeyValuePair<,>));
    127       RegisterTypeAndFullName(typeof(Tuple<>));
    128       RegisterTypeAndFullName(typeof(Tuple<,>));
    129       RegisterTypeAndFullName(typeof(Tuple<,,>));
    130       RegisterTypeAndFullName(typeof(Tuple<,,,>));
    131       RegisterTypeAndFullName(typeof(Tuple<,,,,>));
    132       RegisterTypeAndFullName(typeof(Tuple<,,,,,>));
    133       RegisterTypeAndFullName(typeof(Tuple<,,,,,,>));
    134       RegisterTypeAndFullName(typeof(Tuple<,,,,,,,>));
    135       RegisterTypeAndFullName(typeof(Nullable<>));
    136       RegisterTypeAndFullName(typeof(string));
    137 
    138       RegisterTypeAndFullName(typeof(Array));
    139       RegisterTypeAndFullName(typeof(bool[]));
    140       RegisterTypeAndFullName(typeof(byte[]));
    141       RegisterTypeAndFullName(typeof(sbyte[]));
    142       RegisterTypeAndFullName(typeof(short[]));
    143       RegisterTypeAndFullName(typeof(ushort[]));
    144       RegisterTypeAndFullName(typeof(char[]));
    145       RegisterTypeAndFullName(typeof(int[]));
    146       RegisterTypeAndFullName(typeof(uint[]));
    147       RegisterTypeAndFullName(typeof(long[]));
    148       RegisterTypeAndFullName(typeof(ulong[]));
    149       RegisterTypeAndFullName(typeof(float[]));
    150       RegisterTypeAndFullName(typeof(double[]));
    151       RegisterTypeAndFullName(typeof(string[]));
    152       RegisterTypeAndFullName(typeof(List<>));
    153       RegisterTypeAndFullName(typeof(ArrayList));
    154       RegisterTypeAndFullName(typeof(HashSet<>));
    155       RegisterTypeAndFullName(typeof(Stack<>));
    156       RegisterTypeAndFullName(typeof(Stack));
    157       RegisterTypeAndFullName(typeof(Queue<>));
    158       RegisterTypeAndFullName(typeof(Queue));
    159       RegisterTypeAndFullName(typeof(Dictionary<,>));
    160 
    161       foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
    162         foreach (var t in asm.GetTypes().Where(x => StorableClassAttribute.IsStorableClass(x) || x.IsValueType && !x.IsPrimitive && !x.IsEnum && x.IsSealed))
    163           RegisterTypeAndFullName(t);
    164       }
    165 
    166       var registeredTypes = type2Guid.Keys.ToArray();
    167       foreach (var t in registeredTypes) {
    168         AddBaseTypesRec(t);
    169       }
     106      //RegisterTypeAndFullName(typeof(object));
     107      //RegisterTypeAndFullName(typeof(bool));
     108      //RegisterTypeAndFullName(typeof(byte));
     109      //RegisterTypeAndFullName(typeof(sbyte));
     110      //RegisterTypeAndFullName(typeof(short));
     111      //RegisterTypeAndFullName(typeof(ushort));
     112      //RegisterTypeAndFullName(typeof(char));
     113      //RegisterTypeAndFullName(typeof(int));
     114      //RegisterTypeAndFullName(typeof(uint));
     115      //RegisterTypeAndFullName(typeof(long));
     116      //RegisterTypeAndFullName(typeof(ulong));
     117      //RegisterTypeAndFullName(typeof(float));
     118      //RegisterTypeAndFullName(typeof(double));
     119      //RegisterTypeAndFullName(typeof(decimal));
     120      //RegisterTypeAndFullName(typeof(DateTime));
     121      //RegisterTypeAndFullName(typeof(TimeSpan));
     122      //RegisterTypeAndFullName(typeof(Font));
     123      //RegisterTypeAndFullName(typeof(Color));
     124      //RegisterTypeAndFullName(typeof(Bitmap));
     125      //RegisterTypeAndFullName(typeof(Point));
     126      //RegisterTypeAndFullName(typeof(KeyValuePair<,>));
     127      //RegisterTypeAndFullName(typeof(Tuple<>));
     128      //RegisterTypeAndFullName(typeof(Tuple<,>));
     129      //RegisterTypeAndFullName(typeof(Tuple<,,>));
     130      //RegisterTypeAndFullName(typeof(Tuple<,,,>));
     131      //RegisterTypeAndFullName(typeof(Tuple<,,,,>));
     132      //RegisterTypeAndFullName(typeof(Tuple<,,,,,>));
     133      //RegisterTypeAndFullName(typeof(Tuple<,,,,,,>));
     134      //RegisterTypeAndFullName(typeof(Tuple<,,,,,,,>));
     135      //RegisterTypeAndFullName(typeof(Nullable<>));
     136      //RegisterTypeAndFullName(typeof(string));
     137
     138      //RegisterTypeAndFullName(typeof(Array));
     139      //RegisterTypeAndFullName(typeof(bool[]));
     140      //RegisterTypeAndFullName(typeof(byte[]));
     141      //RegisterTypeAndFullName(typeof(sbyte[]));
     142      //RegisterTypeAndFullName(typeof(short[]));
     143      //RegisterTypeAndFullName(typeof(ushort[]));
     144      //RegisterTypeAndFullName(typeof(char[]));
     145      //RegisterTypeAndFullName(typeof(int[]));
     146      //RegisterTypeAndFullName(typeof(uint[]));
     147      //RegisterTypeAndFullName(typeof(long[]));
     148      //RegisterTypeAndFullName(typeof(ulong[]));
     149      //RegisterTypeAndFullName(typeof(float[]));
     150      //RegisterTypeAndFullName(typeof(double[]));
     151      //RegisterTypeAndFullName(typeof(string[]));
     152      //RegisterTypeAndFullName(typeof(List<>));
     153      //RegisterTypeAndFullName(typeof(ArrayList));
     154      //RegisterTypeAndFullName(typeof(HashSet<>));
     155      //RegisterTypeAndFullName(typeof(Stack<>));
     156      //RegisterTypeAndFullName(typeof(Stack));
     157      //RegisterTypeAndFullName(typeof(Queue<>));
     158      //RegisterTypeAndFullName(typeof(Queue));
     159      //RegisterTypeAndFullName(typeof(Dictionary<,>));
     160
     161      //foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
     162      //  foreach (var t in asm.GetTypes().Where(x => StorableClassAttribute.IsStorableClass(x) // storable classes
     163      //                                           || x.IsValueType && !x.IsPrimitive && !x.IsEnum && x.IsSealed // structs
     164      //                                           || typeof(IEqualityComparer).IsAssignableFrom(x) // equality comparers
     165      //                                           || x.IsGenericType && typeof(IEqualityComparer<>).IsAssignableFrom(x.GetGenericTypeDefinition()))) // generic equality comparers
     166      //    RegisterTypeAndFullName(t);
     167      //}
     168
     169      //var registeredTypes = type2Guid.Keys.ToArray();
     170      //foreach (var t in registeredTypes) {
     171      //  AddBaseTypesRec(t);
     172      //}
    170173
    171174      RegisterExtension(BoolBox.Bool);
     
    195198    }
    196199
    197     private void AddBaseTypesRec(Type t) {
    198       foreach (var interfaceType in t.GetInterfaces()) {
    199         RegisterTypeAndFullName(interfaceType);
    200         AddBaseTypesRec(interfaceType);
    201       }
    202       if (t.BaseType != null) {
    203         RegisterTypeAndFullName(t.BaseType);
    204         AddBaseTypesRec(t.BaseType);
    205       }
    206     }
     200    //private void AddBaseTypesRec(Type t) {
     201    //  foreach (var interfaceType in t.GetInterfaces()) {
     202    //    RegisterTypeAndFullName(interfaceType);
     203    //    AddBaseTypesRec(interfaceType);
     204    //  }
     205    //  if (t.BaseType != null) {
     206    //    RegisterTypeAndFullName(t.BaseType);
     207    //    AddBaseTypesRec(t.BaseType);
     208    //  }
     209    //}
    207210
    208211    public void RegisterTransformer(ITransformer transformer) {
     
    218221    //      }
    219222    //    }
    220     public void RegisterTypeAndFullName(Type type) {
    221       lock (locker) {
    222         var key = type.AssemblyQualifiedName ?? type.Name;
    223         if (!guid2Type.ContainsKey(key)) {
    224           guid2Type.Add(key, type);
    225           type2Guid.Add(type, key);
    226         }
    227       }
    228     }
     223    //public void RegisterTypeAndFullName(Type type) {
     224    //  lock (locker) {
     225    //    var key = type.AssemblyQualifiedName ?? type.Name;
     226    //    if (!guid2Type.ContainsKey(key)) {
     227    //      guid2Type.Add(key, type);
     228    //      type2Guid.Add(type, key);
     229    //    }
     230    //  }
     231    //}
    229232    public void RegisterExtension<TExtension>(GeneratedExtensionBase<TExtension> extension) {
    230233      lock (locker) {
     
    239242      return transformer2Guid[transformer];
    240243    }
    241     public Type GetType(string guid) {
    242       return guid2Type[guid];
    243     }
    244     public string GetGuid(Type type) {
    245       return type2Guid[type];
    246     }
     244    //public Type GetType(string guid) {
     245    //  return guid2Type[guid];
     246    //}
     247    //public string GetGuid(Type type) {
     248    //  return type2Guid[type];
     249    //}
    247250    public TypeInfo GetTypeInfo(Type type) {
    248251      lock (locker) {
  • branches/PersistenceOverhaul/HeuristicLab.Persistence/4.0/Transformers/StorableClassTransformer.cs

    r14549 r14594  
    3030  internal sealed class StorableClassBoxTransformer : BoxTransformer<object> {
    3131    public override bool CanTransformType(Type type) {
    32       return StorableClassAttribute.IsStorableClass(type);
     32      return StorableClassAttribute.IsStorableClass(type) || type.BaseType != null && CanTransformType(type.BaseType);
    3333    }
    3434
     
    7979        uint componentId;
    8080        bool found = components.TryGetValue(mapper.GetStringId(componentInfo.Name), out componentId);
    81         field.SetValue(obj, found ? mapper.GetObject(componentId) : componentInfo.StorableAttribute.DefaultValue);
     81        if (found)
     82          field.SetValue(obj, mapper.GetObject(componentId));
     83        else if (componentInfo.StorableAttribute.DefaultValue != null)
     84          field.SetValue(obj, componentInfo.StorableAttribute.DefaultValue);
    8285      }
    8386
     
    8689        uint componentId;
    8790        bool found = components.TryGetValue(mapper.GetStringId(componentInfo.Name), out componentId);
    88         property.SetValue(obj, found ? mapper.GetObject(componentId) : componentInfo.StorableAttribute.DefaultValue, null);
     91        if (found)
     92          property.SetValue(obj, mapper.GetObject(componentId), null);
     93        else if (componentInfo.StorableAttribute.DefaultValue != null)
     94          property.SetValue(obj, componentInfo.StorableAttribute.DefaultValue, null);
    8995      }
    9096
  • branches/PersistenceOverhaul/HeuristicLab.Persistence/4.0/Transformers/Transformers.cs

    r14549 r14594  
    807807    }
    808808    public override Box ToBox(object o, Mapper mapper) {
    809       Array arr = (Array)o;
    810       if (arr.GetLowerBound(0) != 0 || arr.Rank > 1) throw new NotSupportedException();
    811 
    812809      var box = Box.CreateBuilder();
    813810      box.TransformerId = mapper.GetTransformerId(this);
     
    816813    }
    817814    private void Populate(Box.Builder box, object value, Mapper mapper) {
     815      var type = value.GetType();
    818816      var array = (Array)value;
    819       var elementType = value.GetType().GetElementType();
     817      var rank = array.Rank;
    820818
    821819      var uIntArrayBox = UnsignedIntArrayBox.CreateBuilder();
    822       foreach (var item in (IEnumerable)array)
    823         uIntArrayBox.AddValues(mapper.GetBoxId(item));
    824 
    825       box.TypeId = mapper.GetBoxId(elementType);
     820      uIntArrayBox.AddValues(mapper.GetBoxId(rank));
     821
     822      int[] lengths = new int[rank];
     823      int[] lowerBounds = new int[rank];
     824      for (int i = 0; i < rank; i++) {
     825        lengths[i] = array.GetLength(i);
     826        lowerBounds[i] = array.GetLowerBound(i);
     827      }
     828
     829      uIntArrayBox.AddRangeValues(lengths.Select(x => mapper.GetBoxId(x)));
     830      uIntArrayBox.AddRangeValues(lowerBounds.Select(x => mapper.GetBoxId(x)));
     831
     832      int[] positions = (int[])lowerBounds.Clone();
     833      while (positions[rank - 1] < lengths[rank - 1] + lowerBounds[rank - 1]) {
     834        uIntArrayBox.AddValues(mapper.GetBoxId(array.GetValue(positions)));
     835        positions[0] += 1;
     836        for (int i = 0; i < rank - 1; i++) {
     837          if (positions[i] >= lowerBounds[i] + lengths[i]) {
     838            positions[i] = lowerBounds[i];
     839            positions[i + 1] += 1;
     840          } else {
     841            break;
     842          }
     843        }
     844      }
     845
     846      box.TypeId = mapper.GetBoxId(type);
    826847      box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, uIntArrayBox.Build());
    827848    }
    828849    public override object ToObject(Box box, Mapper mapper) {
    829850      var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray);
     851      var rank = (int)mapper.GetObject(uIntArrayBox.GetValues(0));
     852
     853      int[] lengths = new int[rank], lowerBounds = new int[rank];
     854      for (int i = 0; i < rank; i++)
     855        lengths[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1));
     856      for (int i = 0; i < rank; i++)
     857        lowerBounds[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1 + rank));
     858
    830859      var type = (Type)mapper.GetObject(box.TypeId);
    831       return Array.CreateInstance(type, uIntArrayBox.ValuesCount);
     860      return Array.CreateInstance(type.GetElementType(), lengths, lowerBounds);
    832861    }
    833862    public override void FillFromBox(object obj, Box box, Mapper mapper) {
     863      var array = (Array)obj;
    834864      var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray);
    835       Array.Copy(uIntArrayBox.ValuesList.Select(x => mapper.GetObject(x)).ToArray(), (Array)obj, uIntArrayBox.ValuesCount);
     865      var rank = (int)mapper.GetObject(uIntArrayBox.GetValues(0));
     866
     867      int[] lengths = new int[rank], lowerBounds = new int[rank];
     868      for (int i = 0; i < rank; i++)
     869        lengths[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1));
     870      for (int i = 0; i < rank; i++)
     871        lowerBounds[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1 + rank));
     872
     873      int[] positions = (int[])lowerBounds.Clone();
     874      var e = uIntArrayBox.ValuesList.Skip(1 + 2 * rank).GetEnumerator();
     875      while (e.MoveNext()) {
     876        int[] currentPositions = positions;
     877        array.SetValue(mapper.GetObject(e.Current), currentPositions);
     878        positions[0] += 1;
     879        for (int i = 0; i < rank - 1; i++) {
     880          if (positions[i] >= lengths[i] + lowerBounds[i]) {
     881            positions[i] = lowerBounds[i];
     882            positions[i + 1] += 1;
     883          } else {
     884            break;
     885          }
     886        }
     887      }
    836888    }
    837889  }
     
    857909    private void Populate(Box.Builder box, object value, Mapper mapper) {
    858910      var uIntArrayBox = UnsignedIntArrayBox.CreateBuilder();
     911
     912      var type = value.GetType();
     913      var propertyInfo = type.GetProperty("Comparer");
     914      if (propertyInfo != null) {
     915        // TODO: where to store id for comparer box? (atm: first element in int array ...)
     916        var comparer = propertyInfo.GetValue(value);
     917        var comparerType = comparer.GetType();
     918        if (Default.CompositeSerializers.Storable.StorableClassAttribute.IsStorableClass(comparerType))
     919          uIntArrayBox.AddValues(mapper.GetBoxId(comparer));
     920        else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any())
     921          throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields");
     922        else
     923          uIntArrayBox.AddValues(mapper.GetBoxId(comparerType));
     924      }
     925
    859926      foreach (var item in (IEnumerable)value)
    860927        uIntArrayBox.AddValues(mapper.GetBoxId(item));
    861       box.TypeId = mapper.GetBoxId(value.GetType());
     928
     929      box.TypeId = mapper.GetBoxId(type);
    862930      box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, uIntArrayBox.Build());
    863931    }
     
    865933      var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray);
    866934      var type = (Type)mapper.GetObject(box.TypeId);
    867       return Activator.CreateInstance(type, uIntArrayBox.ValuesCount);
     935      return Activator.CreateInstance(type);
    868936    }
    869937    public override void FillFromBox(object obj, Box box, Mapper mapper) {
     
    871939      var elements = uIntArrayBox.ValuesList.Select(mapper.GetObject);
    872940      var type = obj.GetType();
     941
    873942      string methodName = string.Empty;
    874943      if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Stack<>) || type == typeof(Stack)) {
     
    879948      } else {
    880949        methodName = "Add";
     950        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) {
     951          var fieldInfo = type.GetField("m_comparer", BindingFlags.NonPublic | BindingFlags.Instance);
     952          var comparerObj = mapper.GetObject(uIntArrayBox.GetValues(0));
     953          var comparer = comparerObj is Type ? Activator.CreateInstance((Type)comparerObj) : comparerObj;
     954          fieldInfo.SetValue(obj, comparer);
     955          elements = elements.Skip(1);
     956        }
    881957      }
    882958
     
    909985      var comparer = propertyInfo.GetValue(value);
    910986
    911       dictionaryBox.SetComparerId(mapper.GetBoxId(comparer));
    912       box.TypeId = mapper.GetBoxId(value.GetType());
     987      var comparerType = comparer.GetType();
     988      if (Default.CompositeSerializers.Storable.StorableClassAttribute.IsStorableClass(comparerType))
     989        dictionaryBox.SetComparerId(mapper.GetBoxId(comparer));
     990      else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any())
     991        throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields");
     992      else
     993        dictionaryBox.SetComparerId(mapper.GetBoxId(comparerType));
     994
     995      box.TypeId = mapper.GetBoxId(type);
    913996      box.SetExtension(DictionaryBox.Dictionary, dictionaryBox.Build());
    914997    }
     
    9201003      var type = obj.GetType();
    9211004      var dictionaryBox = box.GetExtension(DictionaryBox.Dictionary);
    922       var comparer = mapper.GetObject(dictionaryBox.ComparerId);
     1005      var comparerObj = mapper.GetObject(dictionaryBox.ComparerId);
     1006      var comparer = comparerObj is Type ? Activator.CreateInstance((Type)comparerObj) : comparerObj;
     1007
     1008      var fieldInfo = type.GetField("comparer", BindingFlags.NonPublic | BindingFlags.Instance);
     1009      fieldInfo.SetValue(obj, comparer);
     1010
     1011
    9231012      var addMethod = type.GetMethod("Add");
    9241013      for (int i = 0; i < dictionaryBox.KeyIdsCount; i++) {
Note: See TracChangeset for help on using the changeset viewer.