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 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 LocalILCodeVariable GenerateDictionaryEnumerateCode(Type type, string refName) { var extType = _il.TypeCache.Extend(type); var dictionaryMembers = new DictionaryMembers(extType); var local = _il.DeclareLocal("dictionary", dictionaryMembers.VariableType); _il.Construct(dictionaryMembers.Constructor); _il.Var.Set(local); NullableMembers keyNullableMembers; ILCodeParameter keyParam; var conditionLabel = _il.DefineLabel(); var bodyLabel = _il.DefineLabel(); var keyType = Members.Nullable.TryGetValue(dictionaryMembers.KeyType, out keyNullableMembers) ? keyNullableMembers.NullableType : dictionaryMembers.KeyType; var keyTypeExt = _il.TypeCache.Extend(keyType); // First of all, transfer to the condition part _il.TransferLong(conditionLabel); // Mark that we enter the body of the loop _il.MarkLabel(bodyLabel); if (keyTypeExt.IsValueOrNullableOfValue()) { keyParam = _il.DeclareLocal("ck", keyType); } else if (keyTypeExt.Class == TypeClass.Dictionary) { keyParam = GenerateDictionaryEnumerateCode(keyType, refName); _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsDictionaryInDictionaryKey); } else if (keyTypeExt.Class == TypeClass.Collection) { keyParam = GenerateCollectionContent(keyTypeExt, refName); _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsCollectionInDictionaryKey); } else { var keyLocal = _il.DeclareLocal("ck", keyType); GenerateCreateAndChildCallCode(keyLocal); keyParam = keyLocal; _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsDictionaryKey); } var throwExceptionLabel = _il.DefineLabel(); ILCodeParameter valueParam; NullableMembers valueNullableMembers; var hasNullableMembers = Members.Nullable.TryGetValue(dictionaryMembers.ValueType, out valueNullableMembers); var valueType = dictionaryMembers.ValueType; var extValueType = valueType.Extend(); if (extValueType.IsValueOrNullableOfValue()) { var loadTrueLabel = _il.DefineLabel(); var checkIfErrorLabel = _il.DefineLabel(); valueParam = _il.DeclareLocal("cv", hasNullableMembers ? valueNullableMembers.NullableType : dictionaryMembers.ValueType); _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorTryVisitValue[dictionaryMembers.ValueType], Members.VisitArgsDictionaryValue, valueParam); _il.TransferLongIfFalse(loadTrueLabel); if (hasNullableMembers) { _il.Snippets.InvokeMethod(valueParam, valueNullableMembers.GetHasValue); _il.Negate(); } else { _il.Snippets.AreEqual(valueParam, null); } _il.TransferLong(checkIfErrorLabel); _il.MarkLabel(loadTrueLabel); _il.LoadValue(true); _il.MarkLabel(checkIfErrorLabel); _il.TransferLongIfTrue(throwExceptionLabel); } else if (extValueType.Class == TypeClass.Dictionary) { var callTryVisitValue = new CallMethodILCode(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsDictionaryInDictionaryValue); _il.Snippets.AreEqual(callTryVisitValue, (int)ValueState.Found); _il.TransferLongIfFalse(throwExceptionLabel); valueParam = GenerateDictionaryEnumerateCode(valueType, refName); _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsDictionaryInDictionaryValue); } else if (extValueType.Class == TypeClass.Collection) { var callTryVisit = new CallMethodILCode(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsCollectionInDictionaryValue); _il.Snippets.AreEqual(callTryVisit, (int)ValueState.Found); _il.TransferLongIfFalse(throwExceptionLabel); valueParam = GenerateCollectionContent(_il.TypeCache.Extend(valueType), refName); _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsCollectionInDictionaryValue); } else { var callTryVisit = new CallMethodILCode(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsDictionaryValue); _il.Snippets.AreEqual(callTryVisit, (int)ValueState.Found); _il.TransferLongIfFalse(throwExceptionLabel); var valueLocal = _il.DeclareLocal("cv", hasNullableMembers ? valueNullableMembers.NullableType : dictionaryMembers.ValueType); GenerateCreateAndChildCallCode(valueLocal); valueParam = valueLocal; _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsDictionaryValue); } _il.Var.Load(local); GenerateLoadParamValueCode(keyParam); GenerateLoadParamValueCode(valueParam); _il.CallVirt(dictionaryMembers.Add); _il.TransferLong(conditionLabel); _il.MarkLabel(throwExceptionLabel); _il.Snippets.Throw(new CallMethodILCode(Members.ExceptionNoDictionaryValue, refName)); _il.MarkLabel(conditionLabel); if (keyTypeExt.IsValueOrNullableOfValue()) { var loadZeroLabel = _il.DefineLabel(); var checkConditionLabel = _il.DefineLabel(); _il.Snippets.InvokeMethod(_visitorVariable, Members.VisitorTryVisitValue[keyType], Members.VisitArgsDictionaryKey, keyParam); _il.TransferLongIfFalse(loadZeroLabel); if (keyType.IsValueType) { _il.Snippets.InvokeMethod(keyParam, Members.Nullable[keyType].GetHasValue); _il.TransferLong(checkConditionLabel); } else { _il.Snippets.AreEqual(keyParam, ILCodeParameter.Null); _il.Negate(); _il.TransferLong(checkConditionLabel); } _il.MarkLabel(loadZeroLabel); _il.LoadValue(false); _il.MarkLabel(checkConditionLabel); _il.TransferLongIfTrue(bodyLabel); } else if (keyTypeExt.Class == TypeClass.Dictionary) { var callTryVisitKey = new CallMethodILCode(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsDictionaryInDictionaryKey); _il.Snippets.AreEqual(callTryVisitKey, (int)ValueState.Found); _il.TransferLongIfTrue(bodyLabel); } else if (keyTypeExt.Class == TypeClass.Collection) { var callTryVisitKey = new CallMethodILCode(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsCollectionInDictionaryKey); _il.Snippets.AreEqual(callTryVisitKey, (int)ValueState.Found); _il.TransferLongIfTrue(bodyLabel); } else { var callTryVisit = new CallMethodILCode(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsDictionaryKey); _il.Snippets.AreEqual(callTryVisit, (int)ValueState.Found); _il.TransferLongIfTrue(bodyLabel); } return local; }
public static ILCodeParameter Of(CallMethodILCode code) { return new ILCodeParameterDelegatable(code.ReturnType, il => il.Generate(code)); }