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); }
public void BuildTravelReadMethod() { var graphArgument = new ILArgPointer(_target.Type, 2); foreach (var property in _target.Properties) { GeneratePropertyCode(graphArgument, property); } _il.Emit(OpCodes.Ret); }
private void GeneratePropertyCode(ILArgPointer graphArg, SerializableProperty target) { var extPropertyType = target.Ext; var argsField = _context.GetArgsField(target); var argsFieldVariable = ILPointer.Field(ILPointer.This(), argsField); if (extPropertyType.IsValueOrNullableOfValue()) { var isNullable = extPropertyType.Classification == TypeClassification.Nullable; var isEnum = extPropertyType.IsEnum(); var isValueType = extPropertyType.Info.IsValueType; var mediatorPropertyType = isEnum ? extPropertyType.GetUnderlyingEnumType() : extPropertyType.Ref; var valueType = !isNullable && isValueType ? Members.Nullable[mediatorPropertyType].NullableType : mediatorPropertyType; var valueLocal = _il.NewLocal(valueType); _il.InvokeMethod(_visitorVariable, Members.VisitorTryVisitValue[valueType], argsFieldVariable, valueLocal); if (isValueType && !isNullable) { var labelValueNotFound = _il.NewLabel(); labelValueNotFound.TransferLongIfFalse(); _il.Load(valueLocal .Call(Members.Nullable[mediatorPropertyType].GetHasValue) .Negate()); var nullableHasValueLabel = _il.NewLabel(); nullableHasValueLabel.TransferLong(); labelValueNotFound.Mark(); _il.Load(true); nullableHasValueLabel.Mark(); } else { _il.Negate(); } var skipSetValueLabel = _il.NewLabel(); skipSetValueLabel.TransferLongIfTrue(); var valueToAdd = isValueType && !isNullable ? valueLocal.Call(Members.Nullable[mediatorPropertyType].GetValue) : valueLocal; _il.Set(graphArg, target.Ref, valueToAdd); skipSetValueLabel.Mark(); } else if (extPropertyType.Classification == TypeClassification.Dictionary) { var stateLocal = _il.NewLocal(typeof(ValueState)); _il.Set(stateLocal, _visitorVariable.Call(Members.VisitorTryVisit, argsFieldVariable)); var endLabel = _il.NewLabel(); endLabel.TransferLongIfTrue(stateLocal.Equal((int)ValueState.NotFound)); _il.AreEqual(stateLocal, (int)ValueState.Found); var nullLabel = _il.NewLabel(); nullLabel.TransferLongIfFalse(); var dictionaryLocal = GenerateDictionaryEnumerateCode(target.Ref.PropertyType, target.Ref.Name); _il.Set(graphArg, target.Ref, dictionaryLocal.Cast(target.Ref.PropertyType)); _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, argsFieldVariable); endLabel.TransferLong(); nullLabel.Mark(); _il.Set(graphArg, target.Ref, null); endLabel.Mark(); } else if (extPropertyType.Classification == TypeClassification.Collection) { _il.InvokeMethod(_visitorVariable, Members.VisitorTryVisit, argsFieldVariable); var stateLocal = _il.NewLocal(typeof(ValueState)); _il.Set(stateLocal); _il.AreEqual(stateLocal, (int)ValueState.NotFound); var endLabel = _il.NewLabel(); endLabel.TransferLongIfTrue(); _il.AreEqual(stateLocal, (int)ValueState.Found); var nullLabel = _il.NewLabel(); nullLabel.TransferLongIfFalse(); var collectionParam = GenerateCollectionContent(extPropertyType, target.Ref.Name); _il.Set(graphArg, target.Ref, collectionParam); _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, argsFieldVariable); endLabel.TransferLong(); nullLabel.Mark(); _il.Set(graphArg, target.Ref, null); endLabel.Mark(); } else { _il.InvokeMethod(_visitorVariable, Members.VisitorTryVisit, argsFieldVariable); var stateLocal = _il.NewLocal(typeof(ValueState)); _il.Set(stateLocal); _il.IfNotEqual(stateLocal, (int)ValueState.NotFound) .Then(() => { _il.IfEqual(stateLocal, (int)ValueState.Found) .Then(() => { var singleLocal = _il.NewLocal(extPropertyType.Ref); GenerateCreateAndChildCallCode(singleLocal); _il.Set(graphArg, target.Ref, singleLocal); _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, argsFieldVariable); }).Else(() => { _il.Set(graphArg, target.Ref, null); }).End(); }).End(); } }