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); }
private ILLocalVariable GenerateDictionaryEnumerateCode(Type type, string refName) { var extType = _typeProvider.Extend(type); var dictionaryMembers = new DictionaryMembers(extType); var local = _il.NewLocal(dictionaryMembers.VariableType); _il.Construct(dictionaryMembers.Constructor); _il.Set(local); var keyType = Members.Nullable.TryGetValue(dictionaryMembers.KeyType, out var keyNullableMembers) ? keyNullableMembers.NullableType : dictionaryMembers.KeyType; var conditionLabel = _il.NewLabel(); var bodyLabel = _il.NewLabel(); var keyTypeExt = _typeProvider.Extend(keyType); // First of all, transfer to the condition part conditionLabel.TransferLong(); // Mark that we enter the body of the loop bodyLabel.Mark(); ILPointer keyParam; if (keyTypeExt.IsValueOrNullableOfValue()) { keyParam = _il.NewLocal(keyType); } else if (keyTypeExt.Classification == TypeClassification.Dictionary) { keyParam = GenerateDictionaryEnumerateCode(keyType, refName); _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsDictionaryInDictionaryKey); } else if (keyTypeExt.Classification == TypeClassification.Collection) { keyParam = GenerateCollectionContent(keyTypeExt, refName); _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsCollectionInDictionaryKey); } else { var keyLocal = _il.NewLocal(keyType); GenerateCreateAndChildCallCode(keyLocal); keyParam = keyLocal; _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsDictionaryKey); } var throwExceptionLabel = _il.NewLabel(); var hasNullableMembers = Members.Nullable.TryGetValue( dictionaryMembers.ValueType, out var valueNullableMembers); var valueType = dictionaryMembers.ValueType; var extValueType = _typeProvider.Extend(valueType); ILPointer valueParam; if (extValueType.IsValueOrNullableOfValue()) { var loadTrueLabel = _il.NewLabel(); var checkIfErrorLabel = _il.NewLabel(); valueParam = _il.NewLocal(hasNullableMembers ? valueNullableMembers.NullableType : dictionaryMembers.ValueType); _il.InvokeMethod(_visitorVariable, Members.VisitorTryVisitValue[dictionaryMembers.ValueType], Members.VisitArgsDictionaryValue, valueParam); loadTrueLabel.TransferLongIfFalse(); if (hasNullableMembers) { _il.InvokeMethod(valueParam, valueNullableMembers.GetHasValue); _il.Negate(); } else { _il.AreEqual(valueParam, null); } checkIfErrorLabel.TransferLong(); loadTrueLabel.Mark(); _il.Load(true); checkIfErrorLabel.Mark(); throwExceptionLabel.TransferLongIfTrue(); } else if (extValueType.Classification == TypeClassification.Dictionary) { var callTryVisitValue = new ILCallMethodSnippet(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsDictionaryInDictionaryValue); _il.AreEqual(callTryVisitValue, (int)ValueState.Found); throwExceptionLabel.TransferLongIfFalse(); valueParam = GenerateDictionaryEnumerateCode(valueType, refName); _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsDictionaryInDictionaryValue); } else if (extValueType.Classification == TypeClassification.Collection) { var callTryVisit = new ILCallMethodSnippet(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsCollectionInDictionaryValue); _il.AreEqual(callTryVisit, (int)ValueState.Found); throwExceptionLabel.TransferLongIfFalse(); valueParam = GenerateCollectionContent(_typeProvider.Extend(valueType), refName); _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsCollectionInDictionaryValue); } else { var callTryVisit = new ILCallMethodSnippet(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsDictionaryValue); _il.AreEqual(callTryVisit, (int)ValueState.Found); throwExceptionLabel.TransferLongIfFalse(); var valueLocal = _il.NewLocal(hasNullableMembers ? valueNullableMembers.NullableType : dictionaryMembers.ValueType); GenerateCreateAndChildCallCode(valueLocal); valueParam = valueLocal; _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsDictionaryValue); } _il.Load(local); GenerateLoadParamValueCode(keyParam); GenerateLoadParamValueCode(valueParam); _il.EmitCall(OpCodes.Callvirt, dictionaryMembers.Add, null); conditionLabel.TransferLong(); throwExceptionLabel.Mark(); _il.Throw(new ILCallMethodSnippet(Members.ExceptionNoDictionaryValue, refName)); conditionLabel.Mark(); if (keyTypeExt.IsValueOrNullableOfValue()) { var loadZeroLabel = _il.NewLabel(); var checkConditionLabel = _il.NewLabel(); _il.InvokeMethod(_visitorVariable, Members.VisitorTryVisitValue[keyType], Members.VisitArgsDictionaryKey, keyParam); loadZeroLabel.TransferLongIfFalse(); if (keyTypeExt.Info.IsValueType) { _il.InvokeMethod(keyParam, Members.Nullable[keyType].GetHasValue); checkConditionLabel.TransferLong(); } else { _il.AreEqual(keyParam, ILPointer.Null); _il.Negate(); checkConditionLabel.TransferLong(); } loadZeroLabel.Mark(); _il.Load(false); checkConditionLabel.Mark(); bodyLabel.TransferLongIfTrue(); } else if (keyTypeExt.Classification == TypeClassification.Dictionary) { var callTryVisitKey = new ILCallMethodSnippet(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsDictionaryInDictionaryKey); _il.AreEqual(callTryVisitKey, (int)ValueState.Found); bodyLabel.TransferLongIfTrue(); } else if (keyTypeExt.Classification == TypeClassification.Collection) { var callTryVisitKey = new ILCallMethodSnippet(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsCollectionInDictionaryKey); _il.AreEqual(callTryVisitKey, (int)ValueState.Found); bodyLabel.TransferLongIfTrue(); } else { var callTryVisit = new ILCallMethodSnippet(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsDictionaryKey); _il.AreEqual(callTryVisit, (int)ValueState.Found); bodyLabel.TransferLongIfTrue(); } return(local); }
private ILPointer GenerateCollectionContent(ExtendedType target, string refName) { var collectionMembers = new CollectionMembers(target); var isValueType = collectionMembers.ElementType.GetTypeInfo().IsValueType; var collectionLocal = _il.NewLocal(collectionMembers.VariableType); var collection = ILPointer.New(collectionMembers.Constructor) .Cast(collectionMembers.VariableType); _il.Set(collectionLocal, collection); var valueLocal = DeclareCollectionItemLocal(collectionMembers.ElementType);; if (collectionMembers.ElementTypeExt.IsValueOrNullableOfValue()) { _il.WhileLoop(il => { // While condition _il.InvokeMethod(_visitorVariable, Members.VisitorTryVisitValue[collectionMembers.ElementType], Members.VisitArgsCollectionItem, valueLocal); var valueNotFoundLabel = _il.NewLabel(); valueNotFoundLabel.TransferLongIfFalse(); if (isValueType) { _il.InvokeMethod(valueLocal, Members.Nullable[collectionMembers.ElementType].GetHasValue); } else { _il.AreEqual(valueLocal, ILPointer.Null); _il.Negate(); } var isNullLabel = _il.NewLabel(); isNullLabel.TransferLong(); valueNotFoundLabel.Mark(); _il.Load(0); isNullLabel.Mark(); }, il => { _il.Load(collectionLocal); GenerateLoadParamValueCode(valueLocal); _il.EmitCall(OpCodes.Callvirt, collectionMembers.Add, null); }); } else if (collectionMembers.ElementTypeExt.Classification == TypeClassification.Dictionary) { _il.WhileLoop(il => { // Condition var callTryVisit = new ILCallMethodSnippet(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsDictionaryInCollection); _il.AreEqual(callTryVisit, (int)ValueState.Found); }, il => { var contentParam = GenerateDictionaryEnumerateCode(collectionMembers.ElementType, refName); _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsDictionaryInCollection); _il.InvokeMethod(collectionLocal, collectionMembers.Add, contentParam); }); } else if (collectionMembers.ElementTypeExt.Classification == TypeClassification.Collection) { _il.WhileLoop(il => { // Condition var callTryVisit = new ILCallMethodSnippet(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsCollectionInCollection); _il.AreEqual(callTryVisit, (int)ValueState.Found); }, il => { var contentParam = GenerateCollectionContent(collectionMembers.ElementTypeExt, refName); _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsCollectionInCollection); _il.InvokeMethod(collectionLocal, collectionMembers.Add, contentParam); }); } else { _il.WhileLoop(il => { var callTryVisit = new ILCallMethodSnippet(_visitorVariable, Members.VisitorTryVisit, Members.VisitArgsCollectionItem); _il.AreEqual(callTryVisit, (int)ValueState.Found); }, il => { GenerateCreateAndChildCallCode(valueLocal); _il.InvokeMethod(_visitorVariable, Members.VisitorLeave, Members.VisitArgsCollectionItem); _il.InvokeMethod(collectionLocal, collectionMembers.Add, valueLocal); }); } if (target.Ref.IsArray) { return(new ILCallMethodSnippet(collectionMembers.ToArray, collectionLocal)); } return(collectionLocal); }