private void GenerateDictionaryCode(ILCodeVariable dictionary, Type elementType)
 {
     var enumerateCode = new ILEnumerateCode(dictionary, (il, it) => {
         GenerateEnumerateContentCode(new InstancePropertyILCodeVariable(it, elementType.GetProperty("Key")), LevelType.DictionaryKey);
         GenerateEnumerateContentCode(new InstancePropertyILCodeVariable(it, elementType.GetProperty("Value")), LevelType.DictionaryValue);
     });
     _il.Generate(enumerateCode);
 }
        private void GenerateEnumerateContentCode(ILCodeParameter valueParam, LevelType level)
        {
            var type = valueParam.ParameterType;
            var extType = _il.TypeCache.Extend(type);

            var visitArgs = GetContentVisitArgs(extType, level);

            if (extType.IsValueOrNullableOfValue()) {
                _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorVisitValue[type], valueParam.AsNullable(), visitArgs);
            }
            else if (extType.Class == TypeClass.Dictionary) {
                var container = extType.Container.AsDictionary();
                var elementType = container.ElementType;

                var dictionaryType = container.DictionaryInterfaceType;

                var dictionaryLocal = _il.DeclareLocal("dictionary", dictionaryType);
                _il.Snippets.SetVariable(dictionaryLocal, valueParam.Cast(dictionaryType));

                _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorVisit, dictionaryLocal, visitArgs);

                var part = new ILEnumerateCode(dictionaryLocal, (il, it) => {
                    GenerateEnumerateContentCode(new InstancePropertyILCodeVariable(it, elementType.GetProperty("Key")), LevelType.DictionaryKey);
                    GenerateEnumerateContentCode(new InstancePropertyILCodeVariable(it, elementType.GetProperty("Value")), LevelType.DictionaryValue);
                });
                _il.Generate(part);

                _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, dictionaryLocal, visitArgs);
            }
            else if (extType.Class == TypeClass.Collection) {
                var container = extType.Container.AsCollection();
                var collectionType = type.IsArray && extType.Container.AsArray().Ranks > 1
                    ? type
                    : container.CollectionInterfaceType;

                var collectionLocal = _il.DeclareLocal("collection", collectionType);
                _il.Snippets.SetVariable(collectionLocal, valueParam.Cast(collectionType));

                _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorVisit, collectionLocal, visitArgs);

                GenerateEnumerateCollectionContentCode(extType, collectionLocal);

                _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, collectionLocal, visitArgs);
            }
            else {
                _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorVisit, valueParam, visitArgs);

                GenerateChildCall(valueParam);

                _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, valueParam, visitArgs);
            }
        }
        private void GenerateEnumerateCollectionContentCode(ExtendedType target, ILCodeParameter collectionParameter)
        {
            ArrayContainerTypeInfo arrayTypeInfo;
            if (target.TryGetArrayTypeInfo(out arrayTypeInfo) && arrayTypeInfo.Ranks > 1) {
                if (arrayTypeInfo.Ranks > 3)
                    throw new NotSupportedException("The serialization engine is limited to 3 ranks in arrays");

                _il.Snippets.ForLoop(0, new CallMethodILCode(collectionParameter, Members.ArrayGetLength, 0), 1,
                    r0 => {
                        _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorVisit, collectionParameter, Members.VisitArgsCollectionInCollection);
                        _il.Snippets.ForLoop(0, new CallMethodILCode(collectionParameter, Members.ArrayGetLength, 1), 1,
                            r1 => {
                                if (arrayTypeInfo.Ranks > 2) {
                                    _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorVisit, collectionParameter, Members.VisitArgsCollectionInCollection);

                                    _il.Snippets.ForLoop(0, new CallMethodILCode(collectionParameter, Members.ArrayGetLength, 1), 1,
                                        r2 => GenerateEnumerateContentCode(
                                            new CallMethodILCode(collectionParameter, target.Ref.GetMethod("Get"), r0, r1, r2),
                                            LevelType.CollectionItem));

                                    _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, collectionParameter, Members.VisitArgsCollectionInCollection);
                                }
                                else {
                                    GenerateEnumerateContentCode(new CallMethodILCode(collectionParameter, target.Ref.GetMethod("Get"), r0, r1), LevelType.CollectionItem);
                                }
                            });
                        _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, collectionParameter, Members.VisitArgsCollectionInCollection);
                    });
            }
            else {
                var part = new ILEnumerateCode(collectionParameter, (il, it) => GenerateEnumerateContentCode(it, LevelType.CollectionItem));
                _il.Generate(part);
            }
        }