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);
            }
        }
        public CollectionMembers(ExtendedType collectionType)
        {
            ArrayContainerTypeInfo arrayTypeInfo;
            if (collectionType.TryGetArrayTypeInfo(out arrayTypeInfo)) {
                if (arrayTypeInfo.Ranks > 3)
                    throw new NotSupportedException("The serialization engine is limited to 3 ranks in arrays");
                if (arrayTypeInfo.Ranks == 3) {
                    var baseType = typeof (ICollection<>);
                    ElementType = baseType.MakeGenericType(baseType.MakeGenericType(arrayTypeInfo.ElementType));
                    ToArray = typeof (ArrayProvider).GetMethod("To3DArray").MakeGenericMethod(arrayTypeInfo.ElementType);
                }
                else if (arrayTypeInfo.Ranks == 2) {
                    ElementType = typeof (ICollection<>).MakeGenericType(arrayTypeInfo.ElementType);
                    ToArray = typeof(ArrayProvider).GetMethod("To2DArray").MakeGenericMethod(arrayTypeInfo.ElementType);
                }
                else {
                    ElementType = arrayTypeInfo.ElementType;
                    ToArray = typeof(ArrayProvider).GetMethod("ToArray").MakeGenericMethod(arrayTypeInfo.ElementType);
                }
            }
            else {
                ElementType = collectionType.Container.AsCollection().ElementType;
            }

            ElementTypeExt = ElementType.Extend();
            VariableType = typeof (ICollection<>).MakeGenericType(ElementType);

            Add = VariableType.GetMethod("Add", new[] { ElementType });
            var instanceType = collectionType.Ref.IsInterface || collectionType.Ref.IsArray
                ? typeof(List<>).MakeGenericType(ElementType)
                : collectionType.Ref;

            Constructor = instanceType.GetConstructor(Type.EmptyTypes);
            if (Constructor == null) throw InvalidGraphException.NoParameterLessConstructor(collectionType.Ref);
        }
        public static void Resolve(Type type, string path, Action<PropertyInfo, ExtendedType> action)
        {
            var propertyNames = path.Split('.');
            var containerType = type;
            foreach (var propertyName in propertyNames) {
                var property = containerType.GetProperty(propertyName);
                var extendedPropertyType = new ExtendedType(property.PropertyType);

                containerType = extendedPropertyType.Class == TypeClass.Collection
                    ? extendedPropertyType.Container.AsCollection().ElementType
                    : property.PropertyType;

                action(property, extendedPropertyType);
            }
        }
        public DictionaryMembers(ExtendedType dictionaryType)
        {
            var container = dictionaryType.Container.AsDictionary();
            KeyType = container.KeyType;
            ValueType = container.ValueType;
            ElementType = container.ElementType;
            VariableType = typeof (IDictionary<,>).MakeGenericType(KeyType, ValueType);

            Add = VariableType.GetMethod("Add", new[] {KeyType, ValueType});
            var instanceType = dictionaryType.Ref.IsInterface
                ? typeof (Dictionary<,>).MakeGenericType(KeyType, ValueType)
                : dictionaryType.Ref;
            Constructor = instanceType.GetConstructor(Type.EmptyTypes);
            if (Constructor == null) throw InvalidGraphException.NoParameterLessConstructor(dictionaryType.Ref);
        }
        public static bool TryGetComplexTypes(ExtendedType type, out Type[] types)
        {
            if (type.Class == TypeClass.Complex) {
                types = new[] { type.Ref };
                return true;
            }
            if (type.Class == TypeClass.Nullable) {
                var elementType = type.Container.AsNullable().ElementType.Extend();
                return TryGetComplexTypes(elementType, out types);
            }
            if (type.Class == TypeClass.Dictionary) {
                var container = type.Container.AsDictionary();
                Type[] keyTypes;
                var hasKeyTypes = TryGetComplexTypes(container.KeyType.Extend(), out keyTypes);

                Type[] valueTypes;
                var hasValueTypes = TryGetComplexTypes(container.ValueType.Extend(), out valueTypes);

                if (!hasKeyTypes && !hasValueTypes) {
                    types = null;
                    return false;
                }

                if (hasKeyTypes && hasValueTypes) types = keyTypes.Concat(valueTypes).ToArray();
                else if (hasKeyTypes) types = keyTypes;
                else types = valueTypes;

                return true;
            }
            if (type.Class == TypeClass.Collection) {
                var elementType = type.Container.AsCollection().ElementType.Extend();
                return TryGetComplexTypes(elementType, out types);
            }

            types = null;
            return false;
        }
        private ILCodeParameter GenerateCollectionContent(ExtendedType target, string refName)
        {
            var collectionMembers = new CollectionMembers(target);
            var isValueType = collectionMembers.ElementType.IsValueType;

            var collectionLocal = _il.DeclareLocal("collection", collectionMembers.VariableType);
            _il.Construct(collectionMembers.Constructor);
            _il.Cast(collectionMembers.VariableType);
            _il.Var.Set(collectionLocal);

            var valueLocal = DeclareCollectionItemLocal("cv", collectionMembers.ElementType); ;

            if (collectionMembers.ElementTypeExt.IsValueOrNullableOfValue()) {
                _il.Snippets.WhileLoop(il => { // While condition
                    _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorTryVisitValue[collectionMembers.ElementType], Members.VisitArgsCollectionItem, valueLocal);

                    var valueNotFoundLabel = _il.DefineLabel();
                    _il.TransferLongIfFalse(valueNotFoundLabel);

                    if (isValueType) {
                        _il.Snippets.InvokeMethod(valueLocal, Members.Nullable[collectionMembers.ElementType].GetHasValue);
                    }
                    else {
                        _il.Snippets.AreEqual(valueLocal, ILCodeParameter.Null);
                        _il.Negate();
                    }

                    var isNullLabel = _il.DefineLabel();
                    _il.TransferLong(isNullLabel);

                    _il.MarkLabel(valueNotFoundLabel);
                    _il.LoadValue(0);
                    _il.MarkLabel(isNullLabel);
                }, il => {
                    _il.Var.Load(collectionLocal);

                    GenerateLoadParamValueCode(valueLocal);

                    _il.CallVirt(collectionMembers.Add);
                });
            }
            else if (collectionMembers.ElementTypeExt.Class == TypeClass.Dictionary) {
                _il.Snippets.WhileLoop(il => { // Condition
                    var callTryVisit = new CallMethodILCode(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsDictionaryInCollection);
                    _il.Snippets.AreEqual(callTryVisit, (int)ValueState.Found);
                }, il => {
                    var contentParam = GenerateDictionaryEnumerateCode(collectionMembers.ElementType, refName);
                    _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsDictionaryInCollection);
                    _il.Snippets.InvokeMethod(collectionLocal, collectionMembers.Add, contentParam);
                });
            }
            else if (collectionMembers.ElementTypeExt.Class == TypeClass.Collection) {
                _il.Snippets.WhileLoop(il => { // Condition
                    var callTryVisit = new CallMethodILCode(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsCollectionInCollection);
                    _il.Snippets.AreEqual(callTryVisit, (int)ValueState.Found);
                }, il => {
                    var contentParam = GenerateCollectionContent(collectionMembers.ElementTypeExt, refName);
                    _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsCollectionInCollection);
                    _il.Snippets.InvokeMethod(collectionLocal, collectionMembers.Add, contentParam);
                });
            }
            else {
                _il.Snippets.WhileLoop(il => {
                    var callTryVisit = new CallMethodILCode(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsCollectionItem);
                    _il.Snippets.AreEqual(callTryVisit, (int)ValueState.Found);
                }, il => {
                    GenerateCreateAndChildCallCode(valueLocal);
                    _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsCollectionItem);
                    _il.Snippets.InvokeMethod(collectionLocal, collectionMembers.Add, valueLocal);
                });
            }
            if (target.Ref.IsArray)
                return new CallMethodILCode(collectionMembers.ToArray, collectionLocal);

            return collectionLocal;
        }
 private TypeReflectionContext(Type type)
 {
     _type = type;
     _extended = type.Extend();
     _properties = new Lazy<IList<PropertyReflectionContext>>(() => ParseProperties(type));
 }
        private ILCodeParameter GetContentVisitArgs(ExtendedType type, LevelType level)
        {
            if (!type.IsValueOrNullableOfValue()) {
                if (type.Class == TypeClass.Dictionary) {
                    if (level == LevelType.DictionaryKey)
                        return Members.VisitArgsDictionaryInDictionaryKey;
                    if (level == LevelType.DictionaryValue)
                        return Members.VisitArgsDictionaryInDictionaryValue;
                    return Members.VisitArgsDictionaryInCollection;
                }

                if (type.Class == TypeClass.Collection) {
                    if (level == LevelType.DictionaryKey)
                        return Members.VisitArgsCollectionInDictionaryKey;

                    if (level == LevelType.DictionaryValue)
                        return Members.VisitArgsCollectionInDictionaryValue;

                    return Members.VisitArgsCollectionInCollection;
                }
            }

            if (level == LevelType.DictionaryKey)
                return Members.VisitArgsDictionaryKey;

            if (level == LevelType.DictionaryValue)
                return Members.VisitArgsDictionaryValue;

            return Members.VisitArgsCollectionItem;
        }
 public SerializableProperty(PropertyInfo @ref, SerializationMetadata metadata)
 {
     _ref = @ref;
     _metadata = metadata;
     _ext = _ref.PropertyType.Extend();
 }