void IterateHandler(AbstractBufferedReader reader, IFieldHandler handler, bool skipping, HashSet <int> knownInlineRefs) { if (handler is ODBDictionaryFieldHandler) { var dictId = reader.ReadVUInt64(); if (!skipping) { var kvHandlers = ((IFieldHandlerWithNestedFieldHandlers)handler).EnumerateNestedFieldHandlers().ToArray(); IterateDict(dictId, kvHandlers[0], kvHandlers[1]); } } else if (handler is DBObjectFieldHandler) { var oid = reader.ReadVInt64(); if (oid == 0) { if (!skipping) { _visitor?.OidReference(0); } } else if (oid <= int.MinValue || oid > 0) { if (!skipping) { _visitor?.OidReference((ulong)oid); IterateOid((ulong)oid); } } else { if (knownInlineRefs != null) { if (knownInlineRefs.Contains((int)oid)) { if (!skipping) { _visitor?.InlineBackRef((int)oid); } return; } if (!skipping) { _visitor?.InlineRef((int)oid); } knownInlineRefs.Add((int)oid); } var tableId = reader.ReadVUInt32(); var version = reader.ReadVUInt32(); if (!skipping) { MarkTableIdVersionFieldInfo(tableId, version); } string tableName; var skip = skipping || _visitor != null && !_visitor.StartInlineObject(tableId, _tableId2Name.TryGetValue(tableId, out tableName) ? tableName : null, version); var tvi = GetTableVersionInfo(tableId, version); for (var i = 0; i < tvi.FieldCount; i++) { var fi = tvi[i]; var skipField = skip || _visitor != null && !_visitor.StartField(fi.Name); IterateHandler(reader, fi.Handler, skipField, new HashSet <int>()); if (!skipField) { _visitor?.EndField(); } } if (!skip) { _visitor?.EndInlineObject(); } } } else if (handler is ListFieldHandler) { var oid = reader.ReadVInt64(); if (oid == 0) { if (!skipping) { _visitor?.OidReference(0); } } else if (oid <= int.MinValue || oid > 0) { if (!skipping) { _visitor?.OidReference((ulong)oid); IterateOid((ulong)oid); } } else { var itemHandler = ((IFieldHandlerWithNestedFieldHandlers)handler).EnumerateNestedFieldHandlers().First(); IterateInlineList(reader, itemHandler, skipping); } } else if (handler is DictionaryFieldHandler) { var oid = reader.ReadVInt64(); if (oid == 0) { if (!skipping) { _visitor?.OidReference(0); } } else if (oid <= int.MinValue || oid > 0) { if (!skipping) { _visitor?.OidReference((ulong)oid); IterateOid((ulong)oid); } } else { var kvHandlers = ((IFieldHandlerWithNestedFieldHandlers)handler).EnumerateNestedFieldHandlers().ToArray(); IterateInlineDict(reader, kvHandlers[0], kvHandlers[1], skipping); } } else if (handler is NullableFieldHandler) { var hasValue = reader.ReadBool(); if (hasValue) { var itemHandler = ((IFieldHandlerWithNestedFieldHandlers)handler).EnumerateNestedFieldHandlers().First(); IterateHandler(reader, itemHandler, skipping, null); } } else if (handler.NeedsCtx() || handler.HandledType() == null) { throw new BTDBException("Don't know how to iterate " + handler.Name); } else { if (skipping || _visitor == null) { Action <AbstractBufferedReader> skipper; if (!_skippers.TryGetValue(handler, out skipper)) { var meth = ILBuilder.Instance.NewMethod <Action <AbstractBufferedReader> >("Skip" + handler.Name); var il = meth.Generator; handler.Skip(il, il2 => il2.Ldarg(0)); il.Ret(); skipper = meth.Create(); _skippers.Add(handler, skipper); } skipper(reader); } else { Func <AbstractBufferedReader, object> loader; if (!_loaders.TryGetValue(handler, out loader)) { var meth = ILBuilder.Instance.NewMethod <Func <AbstractBufferedReader, object> >("Load" + handler.Name); var il = meth.Generator; handler.Load(il, il2 => il2.Ldarg(0)); il.Box(handler.HandledType()).Ret(); loader = meth.Create(); _loaders.Add(handler, loader); } var obj = loader(reader); if (_visitor.NeedScalarAsObject()) { _visitor.ScalarAsObject(obj); } if (_visitor.NeedScalarAsText()) { _visitor.ScalarAsText(obj == null ? "null" : string.Format(CultureInfo.InvariantCulture, "{0}", obj)); } } } }