public DynamicReadTravellerBuilder(MethodBuilder builder, SerializableType target, TravellerContext context)
 {
     _target = target;
     _context = context;
     _il = builder.IL;
     _visitorVariable = new MethodArgILCodeVariable(1, typeof(IReadVisitor));
 }
        public void BuildTraveller()
        {
            if (_classBuilder.IsSealed)
            {
                throw new InvalidOperationException("Classification builder is sealed");
            }
            var target          = _typeProvider.GetOrCreate(_type);
            var members         = _dtContext.Members;
            var factoryArgument = new ILArgPointer(members.VisitArgsFactoryType, 1);


            var childTravellers = new Dictionary <Type, ChildTravellerInfo>();
            var argFields       = new Dictionary <SerializableProperty, FieldInfo>();

            var il             = _constructorBuilder.IL;
            var travellerIndex = 0;

            foreach (var property in target.Properties)
            {
                var argField      = _classBuilder.DefinePrivateField("_arg" + property.Ref.Name, members.VisitArgsType);
                var visitArgsCode = new ILCallMethodSnippet(factoryArgument, members.ConstructVisitArgsMethod, property.Ref.Name);
                il.Set(ILPointer.This(), argField, visitArgsCode);
                argFields.Add(property, argField);

                if (!ReflectionAnalyzer.TryGetComplexTypes(property.Ext, out var types))
                {
                    continue;
                }

                foreach (var type in types)
                {
                    if (childTravellers.ContainsKey(type))
                    {
                        continue;
                    }

                    var dynamicTraveller = _dtContext.Get(type);
                    var interfaceType    = typeof(IGraphTraveller <>).MakeGenericType(type);
                    var fieldBuilder     = _classBuilder.DefinePrivateField(string.Concat("_traveller", type.Name, ++travellerIndex), interfaceType);
                    childTravellers.Add(type, new ChildTravellerInfo {
                        Field             = fieldBuilder,
                        TravelWriteMethod = dynamicTraveller.TravelWriteMethod,
                        TravelReadMethod  = dynamicTraveller.TravelReadMethod
                    });

                    var getFactoryCode = ILSnippet.Call(factoryArgument, members.ConstructVisitArgsWithTypeMethod, type);
                    var newTraveller   = ILPointer.New(dynamicTraveller.Constructor, getFactoryCode);
                    il.Set(ILPointer.This(), fieldBuilder, newTraveller);
                }
            }
            il.Emit(OpCodes.Ret);

            var context = new TravellerContext(childTravellers, argFields);

            BuildWriteMethods(target, context);
            BuildReadMethods(target, context);

            _classBuilder.Seal();
            DynamicTraveller.Complete(_classBuilder.Type);
        }
 public DynamicReadTravellerBuilder(MethodBuilder builder, SerializableType target, TravellerContext context, ITypeProvider typeProvider)
 {
     _target          = target;
     _context         = context;
     _typeProvider    = typeProvider;
     _il              = builder.IL;
     _visitorVariable = new ILArgPointer(typeof(IReadVisitor), 1);
 }
        private void BuildReadMethods(SerializableType target, TravellerContext context)
        {
            var typedMethodBuilder = _travelReadMethod;
            var readBuilder        = new DynamicReadTravellerBuilder(typedMethodBuilder, target, context, _typeProvider.Provider);

            readBuilder.BuildTravelReadMethod();

            var untypedMethodBuilder = _classBuilder.DefineOverloadMethod("Travel", typeof(void), new[] { typeof(IReadVisitor), typeof(object) });
            var il = untypedMethodBuilder.IL;

            il.InvokeMethod(ILPointer.This(),
                            typedMethodBuilder.Method,
                            ILPointer.Arg(1, typeof(IReadVisitor)),
                            ILPointer.Arg(2, typeof(object)).Cast(target.Type));

            il.Emit(OpCodes.Ret);
        }
        public void BuildTraveller()
        {
            if (_classBuilder.IsSealed) throw new InvalidOperationException("Class builder is sealed");
            var target = _typeProvider.GetOrCreate(_type);
            var members = _dtContext.Members;
            var factoryArgument = new MethodArgILCodeVariable(1, members.VisitArgsFactoryType);

            var childTravellers = new Dictionary<Type, ChildTravellerInfo>();
            var argFields = new Dictionary<SerializableProperty, FieldInfo>();

            var travellerIndex = 0;
            foreach (var property in target.Properties) {
                var argField = _classBuilder.DefinePrivateField("_arg" + property.Ref.Name, members.VisitArgsType);
                var visitArgsCode = new CallMethodILCode(factoryArgument, members.ConstructVisitArgsMethod, property.Ref.Name);
                _constructorBuilder.IL.SetField(argField, visitArgsCode);
                argFields.Add(property, argField);

                Type[] types;
                if (!ReflectionAnalyzer.TryGetComplexTypes(property.Ext, out types)) continue;

                foreach (var type in types) {
                    if (childTravellers.ContainsKey(type)) continue;

                    var dynamicTraveller = _dtContext.Get(type);
                    var interfaceType = typeof (IGraphTraveller<>).MakeGenericType(type);
                    var fieldBuilder = _classBuilder.DefinePrivateField(string.Concat("_traveller", type.Name, ++travellerIndex), interfaceType);
                    childTravellers.Add(type, new ChildTravellerInfo {
                        Field = fieldBuilder,
                        TravelWriteMethod = dynamicTraveller.TravelWriteMethod,
                        TravelReadMethod = dynamicTraveller.TravelReadMethod
                    });

                    var getFactoryCode = new CallMethodILCode(factoryArgument, members.ConstructVisitArgsWithTypeMethod, type);
                    var callConstructorCode = new CallConstructorILCode(dynamicTraveller.Constructor, getFactoryCode);
                    _constructorBuilder.IL.SetField(fieldBuilder, callConstructorCode);

                    //_constructorBuilder.IL.SetField(fieldBuilder, dynamicTraveller.Constructor);
                }
            }
            _constructorBuilder.IL.Return();

            var context = new TravellerContext(childTravellers, argFields);
            BuildWriteMethods(target, context);
            BuildReadMethods(target, context);

            _classBuilder.Seal();
            _dynamicTraveller.Complete(_classBuilder.Type);
        }
        private void BuildWriteMethods(SerializableType target, TravellerContext context)
        {
            var typedMethodBuilder = _travelWriteMethod;
            var writeBuilder = new DynamicWriteTravellerBuilder(typedMethodBuilder, target, context);
            writeBuilder.BuildTravelWriteMethod();

            var untypedMethodBuilder = _classBuilder.DefineOverloadMethod("Travel", typeof(void), new[] { typeof(IWriteVisitor), typeof(object) });
            var il = untypedMethodBuilder.IL;
            il.LoadThis();
            il.Var.Load(new MethodArgILCodeVariable(1, typeof(IWriteVisitor)));
            il.Var.Load(new MethodArgILCodeVariable(2, typeof(object)));
            il.Cast(target.Type);
            il.Call(typedMethodBuilder.Method);
            il.Return();
        }