void WriteLiteralStructMethod(StructMapping structMapping) { string methodName = (string)MethodNames[structMapping]; string typeName = structMapping.TypeDesc.CSharpName; ilg = new CodeGenerator(this.typeBuilder); List<Type> argTypes = new List<Type>(); List<string> argNames = new List<string>(); if (structMapping.TypeDesc.IsNullable) { argTypes.Add(typeof(Boolean)); argNames.Add("isNullable"); } argTypes.Add(typeof(Boolean)); argNames.Add("checkType"); ilg.BeginMethod( structMapping.TypeDesc.Type, GetMethodBuilder(methodName), argTypes.ToArray(), argNames.ToArray(), CodeGenerator.PrivateMethodAttributes); LocalBuilder locXsiType = ilg.DeclareLocal(typeof(XmlQualifiedName), "xsiType"); LocalBuilder locIsNull = ilg.DeclareLocal(typeof(Boolean), "isNull"); MethodInfo XmlSerializationReader_GetXsiType = typeof(XmlSerializationReader).GetMethod( "GetXsiType", CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); MethodInfo XmlSerializationReader_ReadNull = typeof(XmlSerializationReader).GetMethod( "ReadNull", CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); Label labelTrue = ilg.DefineLabel(); Label labelEnd = ilg.DefineLabel(); ilg.Ldarg("checkType"); ilg.Brtrue(labelTrue); ilg.Load(null); ilg.Br_S(labelEnd); ilg.MarkLabel(labelTrue); ilg.Ldarg(0); ilg.Call(XmlSerializationReader_GetXsiType); ilg.MarkLabel(labelEnd); ilg.Stloc(locXsiType); ilg.Ldc(false); ilg.Stloc(locIsNull); if (structMapping.TypeDesc.IsNullable) { ilg.Ldarg("isNullable"); ilg.If(); { ilg.Ldarg(0); ilg.Call(XmlSerializationReader_ReadNull); ilg.Stloc(locIsNull); } ilg.EndIf(); } ilg.Ldarg("checkType"); ilg.If(); // if (checkType) if (structMapping.TypeDesc.IsRoot) { ilg.Ldloc(locIsNull); ilg.If(); ilg.Ldloc(locXsiType); ilg.Load(null); ilg.If(Cmp.NotEqualTo); MethodInfo XmlSerializationReader_ReadTypedNull = typeof(XmlSerializationReader).GetMethod( "ReadTypedNull", CodeGenerator.InstanceBindingFlags, null, new Type[] { locXsiType.LocalType }, null ); ilg.Ldarg(0); ilg.Ldloc(locXsiType); ilg.Call(XmlSerializationReader_ReadTypedNull); ilg.Stloc(ilg.ReturnLocal); ilg.Br(ilg.ReturnLabel); ilg.Else(); if (structMapping.TypeDesc.IsValueType) { throw CodeGenerator.NotSupported("Arg_NeverValueType"); } else { ilg.Load(null); ilg.Stloc(ilg.ReturnLocal); ilg.Br(ilg.ReturnLabel); } ilg.EndIf(); // if (xsiType != null) ilg.EndIf(); // if (isNull) } ilg.Ldloc(typeof(XmlQualifiedName), "xsiType"); ilg.Load(null); ilg.Ceq(); if (!structMapping.TypeDesc.IsRoot) { labelTrue = ilg.DefineLabel(); labelEnd = ilg.DefineLabel(); // xsiType == null ilg.Brtrue(labelTrue); WriteQNameEqual("xsiType", structMapping.TypeName, structMapping.Namespace); // Bool result for WriteQNameEqual is on the stack ilg.Br_S(labelEnd); ilg.MarkLabel(labelTrue); ilg.Ldc(true); ilg.MarkLabel(labelEnd); } ilg.If(); // if (xsiType == null if (structMapping.TypeDesc.IsRoot) { ConstructorInfo XmlQualifiedName_ctor = typeof(XmlQualifiedName).GetConstructor( CodeGenerator.InstanceBindingFlags, null, new Type[] { typeof(String), typeof(String) }, null ); MethodInfo XmlSerializationReader_ReadTypedPrimitive = typeof(XmlSerializationReader).GetMethod( "ReadTypedPrimitive", CodeGenerator.InstanceBindingFlags, null, new Type[] { typeof(XmlQualifiedName) }, null ); ilg.Ldarg(0); ilg.Ldstr(Soap.UrType); ilg.Ldstr(XmlSchema.Namespace); ilg.New(XmlQualifiedName_ctor); ilg.Call(XmlSerializationReader_ReadTypedPrimitive); ilg.Stloc(ilg.ReturnLocal); ilg.Br(ilg.ReturnLabel); } WriteDerivedTypes(structMapping, !structMapping.TypeDesc.IsRoot, typeName); if (structMapping.TypeDesc.IsRoot) WriteEnumAndArrayTypes(); ilg.Else(); // if (xsiType == null if (structMapping.TypeDesc.IsRoot) { MethodInfo XmlSerializationReader_ReadTypedPrimitive = typeof(XmlSerializationReader).GetMethod( "ReadTypedPrimitive", CodeGenerator.InstanceBindingFlags, null, new Type[] { locXsiType.LocalType }, null ); ilg.Ldarg(0); ilg.Ldloc(locXsiType); ilg.Call(XmlSerializationReader_ReadTypedPrimitive); ilg.Stloc(ilg.ReturnLocal); ilg.Br(ilg.ReturnLabel); } else { MethodInfo XmlSerializationReader_CreateUnknownTypeException = typeof(XmlSerializationReader).GetMethod( "CreateUnknownTypeException", CodeGenerator.InstanceBindingFlags, null, new Type[] { typeof(XmlQualifiedName) }, null ); ilg.Ldarg(0); ilg.Ldloc(locXsiType); ilg.Call(XmlSerializationReader_CreateUnknownTypeException); ilg.Throw(); } ilg.EndIf(); // if (xsiType == null ilg.EndIf(); // checkType if (structMapping.TypeDesc.IsNullable) { ilg.Ldloc(typeof(bool), "isNull"); ilg.If(); { ilg.Load(null); ilg.Stloc(ilg.ReturnLocal); ilg.Br(ilg.ReturnLabel); } ilg.EndIf(); } if (structMapping.TypeDesc.IsAbstract) { MethodInfo XmlSerializationReader_CreateAbstractTypeException = typeof(XmlSerializationReader).GetMethod( "CreateAbstractTypeException", CodeGenerator.InstanceBindingFlags, null, new Type[] { typeof(String), typeof(String) }, null ); ilg.Ldarg(0); ilg.Ldstr(structMapping.TypeName); ilg.Ldstr(structMapping.Namespace); ilg.Call(XmlSerializationReader_CreateAbstractTypeException); ilg.Throw(); } else { if (structMapping.TypeDesc.Type != null && typeof(XmlSchemaObject).IsAssignableFrom(structMapping.TypeDesc.Type)) { MethodInfo XmlSerializationReader_set_DecodeName = typeof(XmlSerializationReader).GetMethod( "set_DecodeName", CodeGenerator.InstanceBindingFlags, null, new Type[] { typeof(Boolean) }, null ); ilg.Ldarg(0); ilg.Ldc(false); ilg.Call(XmlSerializationReader_set_DecodeName); } WriteCreateMapping(structMapping, "o"); LocalBuilder oLoc = ilg.GetLocal("o"); // this method populates the memberInfos dictionary based on the structMapping MemberMapping[] mappings = TypeScope.GetSettableMembers(structMapping, memberInfos); Member anyText = null; Member anyElement = null; Member anyAttribute = null; bool isSequence = structMapping.HasExplicitSequence(); ArrayList arraysToDeclareList = new ArrayList(mappings.Length); ArrayList arraysToSetList = new ArrayList(mappings.Length); ArrayList allMembersList = new ArrayList(mappings.Length); for (int i = 0; i < mappings.Length; i++) { MemberMapping mapping = mappings[i]; CodeIdentifier.CheckValidIdentifier(mapping.Name); string source = RaCodeGen.GetStringForMember("o", mapping.Name, structMapping.TypeDesc); Member member = new Member(this, source, "a", i, mapping, GetChoiceIdentifierSource(mapping, "o", structMapping.TypeDesc)); if (!mapping.IsSequence) member.ParamsReadSource = "paramsRead[" + i.ToString(CultureInfo.InvariantCulture) + "]"; member.IsNullable = mapping.TypeDesc.IsNullable; if (mapping.CheckSpecified == SpecifiedAccessor.ReadWrite) member.CheckSpecifiedSource = RaCodeGen.GetStringForMember("o", mapping.Name + "Specified", structMapping.TypeDesc); if (mapping.Text != null) anyText = member; if (mapping.Attribute != null && mapping.Attribute.Any) anyAttribute = member; if (!isSequence) { // find anyElement if present. for (int j = 0; j < mapping.Elements.Length; j++) { if (mapping.Elements[j].Any && (mapping.Elements[j].Name == null || mapping.Elements[j].Name.Length == 0)) { anyElement = member; break; } } } else if (mapping.IsParticle && !mapping.IsSequence) { StructMapping declaringMapping; structMapping.FindDeclaringMapping(mapping, out declaringMapping, structMapping.TypeName); throw new InvalidOperationException(Res.GetString(Res.XmlSequenceHierarchy, structMapping.TypeDesc.FullName, mapping.Name, declaringMapping.TypeDesc.FullName, "Order")); } if (mapping.Attribute == null && mapping.Elements.Length == 1 && mapping.Elements[0].Mapping is ArrayMapping) { Member arrayMember = new Member(this, source, source, "a", i, mapping, GetChoiceIdentifierSource(mapping, "o", structMapping.TypeDesc)); arrayMember.CheckSpecifiedSource = member.CheckSpecifiedSource; allMembersList.Add(arrayMember); } else { allMembersList.Add(member); } if (mapping.TypeDesc.IsArrayLike) { arraysToDeclareList.Add(member); if (mapping.TypeDesc.IsArrayLike && !(mapping.Elements.Length == 1 && mapping.Elements[0].Mapping is ArrayMapping)) { member.ParamsReadSource = null; // flat arrays -- don't want to count params read. if (member != anyText && member != anyElement) { arraysToSetList.Add(member); } } else if (!mapping.TypeDesc.IsArray) { member.ParamsReadSource = null; // collection } } } if (anyElement != null) arraysToSetList.Add(anyElement); if (anyText != null && anyText != anyElement) arraysToSetList.Add(anyText); Member[] arraysToDeclare = (Member[])arraysToDeclareList.ToArray(typeof(Member)); Member[] arraysToSet = (Member[])arraysToSetList.ToArray(typeof(Member)); Member[] allMembers = (Member[])allMembersList.ToArray(typeof(Member)); WriteMemberBegin(arraysToDeclare); WriteParamsRead(mappings.Length); WriteAttributes(allMembers, anyAttribute, "UnknownNode", oLoc); if (anyAttribute != null) WriteMemberEnd(arraysToDeclare); MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); MethodInfo XmlReader_MoveToElement = typeof(XmlReader).GetMethod( "MoveToElement", CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); ilg.Call(XmlReader_MoveToElement); ilg.Pop(); MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod( "get_IsEmptyElement", CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); ilg.Call(XmlReader_get_IsEmptyElement); ilg.If(); MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod( "Skip", CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); ilg.Call(XmlReader_Skip); WriteMemberEnd(arraysToSet); ilg.Ldloc(oLoc); ilg.Stloc(ilg.ReturnLocal); ilg.Br(ilg.ReturnLabel); ilg.EndIf(); MethodInfo XmlReader_ReadStartElement = typeof(XmlReader).GetMethod( "ReadStartElement", CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); ilg.Call(XmlReader_ReadStartElement); if (IsSequence(allMembers)) { ilg.Ldc(0); ilg.Stloc(typeof(Int32), "state"); } int loopIndex = WriteWhileNotLoopStart(); string unknownNode = "UnknownNode((object)o, " + ExpectedElements(allMembers) + ");"; WriteMemberElements(allMembers, unknownNode, unknownNode, anyElement, anyText); MethodInfo XmlReader_MoveToContent = typeof(XmlReader).GetMethod( "MoveToContent", CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); ilg.Call(XmlReader_MoveToContent); ilg.Pop(); WriteWhileLoopEnd(loopIndex); WriteMemberEnd(arraysToSet); MethodInfo XmlSerializationReader_ReadEndElement = typeof(XmlSerializationReader).GetMethod( "ReadEndElement", CodeGenerator.InstanceBindingFlags, null, CodeGenerator.EmptyTypeArray, null ); ilg.Ldarg(0); ilg.Call(XmlSerializationReader_ReadEndElement); ilg.Ldloc(structMapping.TypeDesc.Type, "o"); ilg.Stloc(ilg.ReturnLocal); } ilg.MarkLabel(ilg.ReturnLabel); ilg.Ldloc(ilg.ReturnLocal); ilg.EndMethod(); }
private string GenerateMembersElement(XmlMembersMapping xmlMembersMapping) { ElementAccessor element = xmlMembersMapping.Accessor; MembersMapping mapping = (MembersMapping)element.Mapping; bool hasWrapperElement = mapping.HasWrapperElement; bool writeAccessors = mapping.WriteAccessors; string methodName = NextMethodName(element.Name); ilg = new CodeGenerator(this.typeBuilder); ilg.BeginMethod( typeof(void), methodName, new Type[] { typeof(object[]) }, new string[] { "p" }, CodeGenerator.PublicMethodAttributes ); MethodInfo XmlSerializationWriter_WriteStartDocument = typeof(XmlSerializationWriter).GetMethod( "WriteStartDocument", CodeGenerator.InstanceBindingFlags, Array.Empty<Type>() ); ilg.Ldarg(0); ilg.Call(XmlSerializationWriter_WriteStartDocument); MethodInfo XmlSerializationWriter_TopLevelElement = typeof(XmlSerializationWriter).GetMethod( "TopLevelElement", CodeGenerator.InstanceBindingFlags, Array.Empty<Type>() ); ilg.Ldarg(0); ilg.Call(XmlSerializationWriter_TopLevelElement); // in the top-level method add check for the parameters length, // because visual basic does not have a concept of an <out> parameter it uses <ByRef> instead // so sometime we think that we have more parameters then supplied LocalBuilder pLengthLoc = ilg.DeclareLocal(typeof(int), "pLength"); ilg.Ldarg("p"); ilg.Ldlen(); ilg.Stloc(pLengthLoc); if (hasWrapperElement) { WriteStartElement(element.Name, (element.Form == XmlSchemaForm.Qualified ? element.Namespace : ""), false); int xmlnsMember = FindXmlnsIndex(mapping.Members); if (xmlnsMember >= 0) { MemberMapping member = mapping.Members[xmlnsMember]; string source = "((" + typeof(XmlSerializerNamespaces).FullName + ")p[" + xmlnsMember.ToString(CultureInfo.InvariantCulture) + "])"; ilg.Ldloc(pLengthLoc); ilg.Ldc(xmlnsMember); ilg.If(Cmp.GreaterThan); WriteNamespaces(source); ilg.EndIf(); } for (int i = 0; i < mapping.Members.Length; i++) { MemberMapping member = mapping.Members[i]; if (member.Attribute != null && !member.Ignore) { SourceInfo source = new SourceInfo("p[" + i.ToString(CultureInfo.InvariantCulture) + "]", null, null, pLengthLoc.LocalType.GetElementType(), ilg); SourceInfo specifiedSource = null; int specifiedPosition = 0; if (member.CheckSpecified != SpecifiedAccessor.None) { string memberNameSpecified = member.Name + "Specified"; for (int j = 0; j < mapping.Members.Length; j++) { if (mapping.Members[j].Name == memberNameSpecified) { specifiedSource = new SourceInfo("((bool)p[" + j.ToString(CultureInfo.InvariantCulture) + "])", null, null, typeof(bool), ilg); specifiedPosition = j; break; } } } ilg.Ldloc(pLengthLoc); ilg.Ldc(i); ilg.If(Cmp.GreaterThan); if (specifiedSource != null) { Label labelTrue = ilg.DefineLabel(); Label labelEnd = ilg.DefineLabel(); ilg.Ldloc(pLengthLoc); ilg.Ldc(specifiedPosition); ilg.Ble(labelTrue); specifiedSource.Load(typeof(bool)); ilg.Br_S(labelEnd); ilg.MarkLabel(labelTrue); ilg.Ldc(true); ilg.MarkLabel(labelEnd); ilg.If(); } WriteMember(source, member.Attribute, member.TypeDesc, "p"); if (specifiedSource != null) { ilg.EndIf(); } ilg.EndIf(); } } } for (int i = 0; i < mapping.Members.Length; i++) { MemberMapping member = mapping.Members[i]; if (member.Xmlns != null) continue; if (member.Ignore) continue; SourceInfo specifiedSource = null; int specifiedPosition = 0; if (member.CheckSpecified != SpecifiedAccessor.None) { string memberNameSpecified = member.Name + "Specified"; for (int j = 0; j < mapping.Members.Length; j++) { if (mapping.Members[j].Name == memberNameSpecified) { specifiedSource = new SourceInfo("((bool)p[" + j.ToString(CultureInfo.InvariantCulture) + "])", null, null, typeof(bool), ilg); specifiedPosition = j; break; } } } ilg.Ldloc(pLengthLoc); ilg.Ldc(i); ilg.If(Cmp.GreaterThan); if (specifiedSource != null) { Label labelTrue = ilg.DefineLabel(); Label labelEnd = ilg.DefineLabel(); ilg.Ldloc(pLengthLoc); ilg.Ldc(specifiedPosition); ilg.Ble(labelTrue); specifiedSource.Load(typeof(bool)); ilg.Br_S(labelEnd); ilg.MarkLabel(labelTrue); ilg.Ldc(true); ilg.MarkLabel(labelEnd); ilg.If(); } string source = "p[" + i.ToString(CultureInfo.InvariantCulture) + "]"; string enumSource = null; if (member.ChoiceIdentifier != null) { for (int j = 0; j < mapping.Members.Length; j++) { if (mapping.Members[j].Name == member.ChoiceIdentifier.MemberName) { enumSource = "((" + mapping.Members[j].TypeDesc.CSharpName + ")p[" + j.ToString(CultureInfo.InvariantCulture) + "]" + ")"; break; } } #if DEBUG // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe if (enumSource == null) throw new InvalidOperationException(SR.Format(SR.XmlInternalErrorDetails, "Can not find " + member.ChoiceIdentifier.MemberName + " in the members mapping.")); #endif } // override writeAccessors choice when we've written a wrapper element WriteMember(new SourceInfo(source, source, null, null, ilg), enumSource, member.ElementsSortedByDerivation, member.Text, member.ChoiceIdentifier, member.TypeDesc, writeAccessors || hasWrapperElement); if (specifiedSource != null) { ilg.EndIf(); } ilg.EndIf(); } if (hasWrapperElement) { WriteEndElement(); } ilg.EndMethod(); return methodName; }