1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
4 namespace System.Runtime.Serialization
7 using System.Collections;
8 using System.Collections.Generic;
9 using System.Reflection;
10 using System.Reflection.Emit;
11 using System.Security;
12 using System.Security.Permissions;
13 using System.Runtime.Serialization.Diagnostics.Application;
17 public delegate void XmlFormatClassWriterDelegate(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context,ClassDataContract dataContract);
18 public delegate void XmlFormatCollectionWriterDelegate(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, CollectionDataContract dataContract);
20 public sealed class XmlFormatWriterGenerator
22 internal delegate void XmlFormatClassWriterDelegate(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, ClassDataContract dataContract);
23 internal delegate void XmlFormatCollectionWriterDelegate(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, CollectionDataContract dataContract);
25 internal sealed class XmlFormatWriterGenerator
28 [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that was produced within an assert.")]
30 CriticalHelper helper;
32 [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.")]
34 public XmlFormatWriterGenerator()
36 helper = new CriticalHelper();
39 [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
41 internal XmlFormatClassWriterDelegate GenerateClassWriter(ClassDataContract classContract)
45 if (TD.DCGenWriterStartIsEnabled())
47 TD.DCGenWriterStart("Class", classContract.UnderlyingType.FullName);
50 return helper.GenerateClassWriter(classContract);
54 if (TD.DCGenWriterStopIsEnabled())
61 [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
63 internal XmlFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionDataContract collectionContract)
67 if (TD.DCGenWriterStartIsEnabled())
69 TD.DCGenWriterStart("Collection", collectionContract.UnderlyingType.FullName);
72 return helper.GenerateCollectionWriter(collectionContract);
77 if (TD.DCGenWriterStopIsEnabled())
84 [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Handles all aspects of IL generation including initializing the DynamicMethod."
85 + " Changes to how IL generated could affect how data is serialized and what gets access to data,"
86 + " therefore we mark it for review so that changes to generation logic are reviewed.")]
90 ArgBuilder xmlWriterArg;
91 ArgBuilder contextArg;
92 ArgBuilder dataContractArg;
93 LocalBuilder objectLocal;
96 LocalBuilder contractNamespacesLocal;
97 LocalBuilder memberNamesLocal;
98 LocalBuilder childElementNamespacesLocal;
100 int childElementIndex = 0;
102 internal XmlFormatClassWriterDelegate GenerateClassWriter(ClassDataContract classContract)
104 ilg = new CodeGenerator();
105 bool memberAccessFlag = classContract.RequiresMemberAccessForWrite(null);
108 ilg.BeginMethod("Write" + classContract.StableName.Name + "ToXml", Globals.TypeOfXmlFormatClassWriterDelegate, memberAccessFlag);
110 catch (SecurityException securityException)
112 if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
114 classContract.RequiresMemberAccessForWrite(securityException);
121 InitArgs(classContract.UnderlyingType);
122 DemandSerializationFormatterPermission(classContract);
123 DemandMemberAccessPermission(memberAccessFlag);
124 if (classContract.IsReadOnlyContract)
126 ThrowIfCannotSerializeReadOnlyTypes(classContract);
128 WriteClass(classContract);
129 return (XmlFormatClassWriterDelegate)ilg.EndMethod();
132 internal XmlFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionDataContract collectionContract)
134 ilg = new CodeGenerator();
135 bool memberAccessFlag = collectionContract.RequiresMemberAccessForWrite(null);
138 ilg.BeginMethod("Write" + collectionContract.StableName.Name + "ToXml", Globals.TypeOfXmlFormatCollectionWriterDelegate, memberAccessFlag);
140 catch (SecurityException securityException)
142 if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
144 collectionContract.RequiresMemberAccessForWrite(securityException);
151 InitArgs(collectionContract.UnderlyingType);
152 DemandMemberAccessPermission(memberAccessFlag);
153 if (collectionContract.IsReadOnlyContract)
155 ThrowIfCannotSerializeReadOnlyTypes(collectionContract);
157 WriteCollection(collectionContract);
158 return (XmlFormatCollectionWriterDelegate)ilg.EndMethod();
161 void InitArgs(Type objType)
163 xmlWriterArg = ilg.GetArg(0);
164 contextArg = ilg.GetArg(2);
165 dataContractArg = ilg.GetArg(3);
167 objectLocal = ilg.DeclareLocal(objType, "objSerialized");
168 ArgBuilder objectArg = ilg.GetArg(1);
171 // Copy the data from the DataTimeOffset object passed in to the DateTimeOffsetAdapter.
172 // DateTimeOffsetAdapter is used here for serialization purposes to bypass the ISerializable implementation
173 // on DateTimeOffset; which does not work in partial trust.
175 if (objType == Globals.TypeOfDateTimeOffsetAdapter)
177 ilg.ConvertValue(objectArg.ArgType, Globals.TypeOfDateTimeOffset);
178 ilg.Call(XmlFormatGeneratorStatics.GetDateTimeOffsetAdapterMethod);
182 ilg.ConvertValue(objectArg.ArgType, objType);
184 ilg.Stloc(objectLocal);
187 void DemandMemberAccessPermission(bool memberAccessFlag)
189 if (memberAccessFlag)
191 ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandMemberAccessPermissionMethod);
195 void DemandSerializationFormatterPermission(ClassDataContract classContract)
197 if (!classContract.HasDataContract && !classContract.IsNonAttributedType)
199 ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandSerializationFormatterPermissionMethod);
203 void ThrowIfCannotSerializeReadOnlyTypes(ClassDataContract classContract)
205 ThrowIfCannotSerializeReadOnlyTypes(XmlFormatGeneratorStatics.ClassSerializationExceptionMessageProperty);
208 void ThrowIfCannotSerializeReadOnlyTypes(CollectionDataContract classContract)
210 ThrowIfCannotSerializeReadOnlyTypes(XmlFormatGeneratorStatics.CollectionSerializationExceptionMessageProperty);
213 void ThrowIfCannotSerializeReadOnlyTypes(PropertyInfo serializationExceptionMessageProperty)
215 ilg.Load(contextArg);
216 ilg.LoadMember(XmlFormatGeneratorStatics.SerializeReadOnlyTypesProperty);
218 ilg.Load(dataContractArg);
219 ilg.LoadMember(serializationExceptionMessageProperty);
221 ilg.Call(XmlFormatGeneratorStatics.ThrowInvalidDataContractExceptionMethod);
225 void InvokeOnSerializing(ClassDataContract classContract)
227 if (classContract.BaseContract != null)
228 InvokeOnSerializing(classContract.BaseContract);
229 if (classContract.OnSerializing != null)
231 ilg.LoadAddress(objectLocal);
232 ilg.Load(contextArg);
233 ilg.Call(XmlFormatGeneratorStatics.GetStreamingContextMethod);
234 ilg.Call(classContract.OnSerializing);
238 void InvokeOnSerialized(ClassDataContract classContract)
240 if (classContract.BaseContract != null)
241 InvokeOnSerialized(classContract.BaseContract);
242 if (classContract.OnSerialized != null)
244 ilg.LoadAddress(objectLocal);
245 ilg.Load(contextArg);
246 ilg.Call(XmlFormatGeneratorStatics.GetStreamingContextMethod);
247 ilg.Call(classContract.OnSerialized);
251 void WriteClass(ClassDataContract classContract)
253 InvokeOnSerializing(classContract);
255 if (classContract.IsISerializable)
256 ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteISerializableMethod, xmlWriterArg, objectLocal);
259 if (classContract.ContractNamespaces.Length > 1)
261 contractNamespacesLocal = ilg.DeclareLocal(typeof(XmlDictionaryString[]), "contractNamespaces");
262 ilg.Load(dataContractArg);
263 ilg.LoadMember(XmlFormatGeneratorStatics.ContractNamespacesField);
264 ilg.Store(contractNamespacesLocal);
267 memberNamesLocal = ilg.DeclareLocal(typeof(XmlDictionaryString[]), "memberNames");
268 ilg.Load(dataContractArg);
269 ilg.LoadMember(XmlFormatGeneratorStatics.MemberNamesField);
270 ilg.Store(memberNamesLocal);
272 for (int i = 0; i < classContract.ChildElementNamespaces.Length; i++)
274 if (classContract.ChildElementNamespaces[i] != null)
276 childElementNamespacesLocal = ilg.DeclareLocal(typeof(XmlDictionaryString[]), "childElementNamespaces");
277 ilg.Load(dataContractArg);
278 ilg.LoadMember(XmlFormatGeneratorStatics.ChildElementNamespacesProperty);
279 ilg.Store(childElementNamespacesLocal);
283 if (classContract.HasExtensionData)
285 LocalBuilder extensionDataLocal = ilg.DeclareLocal(Globals.TypeOfExtensionDataObject, "extensionData");
286 ilg.Load(objectLocal);
287 ilg.ConvertValue(objectLocal.LocalType, Globals.TypeOfIExtensibleDataObject);
288 ilg.LoadMember(XmlFormatGeneratorStatics.ExtensionDataProperty);
289 ilg.Store(extensionDataLocal);
290 ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteExtensionDataMethod, xmlWriterArg, extensionDataLocal, -1);
291 WriteMembers(classContract, extensionDataLocal, classContract);
294 WriteMembers(classContract, null, classContract);
296 InvokeOnSerialized(classContract);
299 int WriteMembers(ClassDataContract classContract, LocalBuilder extensionDataLocal, ClassDataContract derivedMostClassContract)
301 int memberCount = (classContract.BaseContract == null) ? 0 :
302 WriteMembers(classContract.BaseContract, extensionDataLocal, derivedMostClassContract);
304 LocalBuilder namespaceLocal = ilg.DeclareLocal(typeof(XmlDictionaryString), "ns");
305 if (contractNamespacesLocal == null)
307 ilg.Load(dataContractArg);
308 ilg.LoadMember(XmlFormatGeneratorStatics.NamespaceProperty);
311 ilg.LoadArrayElement(contractNamespacesLocal, typeIndex - 1);
312 ilg.Store(namespaceLocal);
314 ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, classContract.Members.Count);
316 for (int i = 0; i < classContract.Members.Count; i++, memberCount++)
318 DataMember member = classContract.Members[i];
319 Type memberType = member.MemberType;
320 LocalBuilder memberValue = null;
321 if (member.IsGetOnlyCollection)
323 ilg.Load(contextArg);
324 ilg.Call(XmlFormatGeneratorStatics.StoreIsGetOnlyCollectionMethod);
326 if (!member.EmitDefaultValue)
328 memberValue = LoadMemberValue(member);
329 ilg.IfNotDefaultValue(memberValue);
331 bool writeXsiType = CheckIfMemberHasConflict(member, classContract, derivedMostClassContract);
332 if (writeXsiType || !TryWritePrimitive(memberType, memberValue, member.MemberInfo, null /*arrayItemIndex*/, namespaceLocal, null /*nameLocal*/, i + childElementIndex))
334 WriteStartElement(memberType, classContract.Namespace, namespaceLocal, null /*nameLocal*/, i + childElementIndex);
335 if (classContract.ChildElementNamespaces[i + childElementIndex] != null)
337 ilg.Load(xmlWriterArg);
338 ilg.LoadArrayElement(childElementNamespacesLocal, i + childElementIndex);
339 ilg.Call(XmlFormatGeneratorStatics.WriteNamespaceDeclMethod);
341 if (memberValue == null)
342 memberValue = LoadMemberValue(member);
343 WriteValue(memberValue, writeXsiType);
346 if (classContract.HasExtensionData)
347 ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteExtensionDataMethod, xmlWriterArg, extensionDataLocal, memberCount);
348 if (!member.EmitDefaultValue)
350 if (member.IsRequired)
353 ilg.Call(null, XmlFormatGeneratorStatics.ThrowRequiredMemberMustBeEmittedMethod, member.Name, classContract.UnderlyingType);
361 childElementIndex += classContract.Members.Count;
365 private LocalBuilder LoadMemberValue(DataMember member)
367 ilg.LoadAddress(objectLocal);
368 ilg.LoadMember(member.MemberInfo);
369 LocalBuilder memberValue = ilg.DeclareLocal(member.MemberType, member.Name + "Value");
370 ilg.Stloc(memberValue);
374 void WriteCollection(CollectionDataContract collectionContract)
376 LocalBuilder itemNamespace = ilg.DeclareLocal(typeof(XmlDictionaryString), "itemNamespace");
377 ilg.Load(dataContractArg);
378 ilg.LoadMember(XmlFormatGeneratorStatics.NamespaceProperty);
379 ilg.Store(itemNamespace);
381 LocalBuilder itemName = ilg.DeclareLocal(typeof(XmlDictionaryString), "itemName");
382 ilg.Load(dataContractArg);
383 ilg.LoadMember(XmlFormatGeneratorStatics.CollectionItemNameProperty);
386 if (collectionContract.ChildElementNamespace != null)
388 ilg.Load(xmlWriterArg);
389 ilg.Load(dataContractArg);
390 ilg.LoadMember(XmlFormatGeneratorStatics.ChildElementNamespaceProperty);
391 ilg.Call(XmlFormatGeneratorStatics.WriteNamespaceDeclMethod);
394 if (collectionContract.Kind == CollectionKind.Array)
396 Type itemType = collectionContract.ItemType;
397 LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i");
399 ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementArrayCountMethod, xmlWriterArg, objectLocal);
401 if (!TryWritePrimitiveArray(collectionContract.UnderlyingType, itemType, objectLocal, itemName, itemNamespace))
403 ilg.For(i, 0, objectLocal);
404 if (!TryWritePrimitive(itemType, null /*value*/, null /*memberInfo*/, i /*arrayItemIndex*/, itemNamespace, itemName, 0 /*nameIndex*/))
406 WriteStartElement(itemType, collectionContract.Namespace, itemNamespace, itemName, 0 /*nameIndex*/);
407 ilg.LoadArrayElement(objectLocal, i);
408 LocalBuilder memberValue = ilg.DeclareLocal(itemType, "memberValue");
409 ilg.Stloc(memberValue);
410 WriteValue(memberValue, false /*writeXsiType*/);
418 MethodInfo incrementCollectionCountMethod = null;
419 switch (collectionContract.Kind)
421 case CollectionKind.Collection:
422 case CollectionKind.List:
423 case CollectionKind.Dictionary:
424 incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountMethod;
426 case CollectionKind.GenericCollection:
427 case CollectionKind.GenericList:
428 incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(collectionContract.ItemType);
430 case CollectionKind.GenericDictionary:
431 incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments()));
434 if (incrementCollectionCountMethod != null)
436 ilg.Call(contextArg, incrementCollectionCountMethod, xmlWriterArg, objectLocal);
439 bool isDictionary = false, isGenericDictionary = false;
440 Type enumeratorType = null;
441 Type[] keyValueTypes = null;
442 if (collectionContract.Kind == CollectionKind.GenericDictionary)
444 isGenericDictionary = true;
445 keyValueTypes = collectionContract.ItemType.GetGenericArguments();
446 enumeratorType = Globals.TypeOfGenericDictionaryEnumerator.MakeGenericType(keyValueTypes);
448 else if (collectionContract.Kind == CollectionKind.Dictionary)
451 keyValueTypes = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
452 enumeratorType = Globals.TypeOfDictionaryEnumerator;
456 enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType;
458 MethodInfo moveNextMethod = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
459 MethodInfo getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
460 if (moveNextMethod == null || getCurrentMethod == null)
462 if (enumeratorType.IsInterface)
464 if (moveNextMethod == null)
465 moveNextMethod = XmlFormatGeneratorStatics.MoveNextMethod;
466 if (getCurrentMethod == null)
467 getCurrentMethod = XmlFormatGeneratorStatics.GetCurrentMethod;
471 Type ienumeratorInterface = Globals.TypeOfIEnumerator;
472 CollectionKind kind = collectionContract.Kind;
473 if (kind == CollectionKind.GenericDictionary || kind == CollectionKind.GenericCollection || kind == CollectionKind.GenericEnumerable)
475 Type[] interfaceTypes = enumeratorType.GetInterfaces();
476 foreach (Type interfaceType in interfaceTypes)
478 if (interfaceType.IsGenericType
479 && interfaceType.GetGenericTypeDefinition() == Globals.TypeOfIEnumeratorGeneric
480 && interfaceType.GetGenericArguments()[0] == collectionContract.ItemType)
482 ienumeratorInterface = interfaceType;
487 if (moveNextMethod == null)
488 moveNextMethod = CollectionDataContract.GetTargetMethodWithName(Globals.MoveNextMethodName, enumeratorType, ienumeratorInterface);
489 if (getCurrentMethod == null)
490 getCurrentMethod = CollectionDataContract.GetTargetMethodWithName(Globals.GetCurrentMethodName, enumeratorType, ienumeratorInterface);
493 Type elementType = getCurrentMethod.ReturnType;
494 LocalBuilder currentValue = ilg.DeclareLocal(elementType, "currentValue");
496 LocalBuilder enumerator = ilg.DeclareLocal(enumeratorType, "enumerator");
497 ilg.Call(objectLocal, collectionContract.GetEnumeratorMethod);
500 ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, Globals.TypeOfIDictionaryEnumerator);
501 ilg.New(XmlFormatGeneratorStatics.DictionaryEnumeratorCtor);
503 else if (isGenericDictionary)
505 Type ctorParam = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes));
506 ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { ctorParam }, null);
507 ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, ctorParam);
508 ilg.New(dictEnumCtor);
510 ilg.Stloc(enumerator);
512 ilg.ForEach(currentValue, elementType, enumeratorType, enumerator, getCurrentMethod);
513 if (incrementCollectionCountMethod == null)
515 ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
517 if (!TryWritePrimitive(elementType, currentValue, null /*memberInfo*/, null /*arrayItemIndex*/, itemNamespace, itemName, 0 /*nameIndex*/))
519 WriteStartElement(elementType, collectionContract.Namespace, itemNamespace, itemName, 0 /*nameIndex*/);
521 if (isGenericDictionary || isDictionary)
523 ilg.Call(dataContractArg, XmlFormatGeneratorStatics.GetItemContractMethod);
524 ilg.Load(xmlWriterArg);
525 ilg.Load(currentValue);
526 ilg.ConvertValue(currentValue.LocalType, Globals.TypeOfObject);
527 ilg.Load(contextArg);
528 ilg.Call(XmlFormatGeneratorStatics.WriteXmlValueMethod);
532 WriteValue(currentValue, false /*writeXsiType*/);
536 ilg.EndForEach(moveNextMethod);
540 bool TryWritePrimitive(Type type, LocalBuilder value, MemberInfo memberInfo, LocalBuilder arrayItemIndex, LocalBuilder ns, LocalBuilder name, int nameIndex)
542 PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);
543 if (primitiveContract == null || primitiveContract.UnderlyingType == Globals.TypeOfObject)
547 if (type.IsValueType)
549 ilg.Load(xmlWriterArg);
553 ilg.Load(contextArg);
554 ilg.Load(xmlWriterArg);
556 // load primitive value
561 else if (memberInfo != null)
563 ilg.LoadAddress(objectLocal);
564 ilg.LoadMember(memberInfo);
568 ilg.LoadArrayElement(objectLocal, arrayItemIndex);
577 ilg.LoadArrayElement(memberNamesLocal, nameIndex);
581 // call method to write primitive
582 ilg.Call(primitiveContract.XmlFormatWriterMethod);
586 bool TryWritePrimitiveArray(Type type, Type itemType, LocalBuilder value, LocalBuilder itemName, LocalBuilder itemNamespace)
588 PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType);
589 if (primitiveContract == null)
592 string writeArrayMethod = null;
593 switch (Type.GetTypeCode(itemType))
595 case TypeCode.Boolean:
596 writeArrayMethod = "WriteBooleanArray";
598 case TypeCode.DateTime:
599 writeArrayMethod = "WriteDateTimeArray";
601 case TypeCode.Decimal:
602 writeArrayMethod = "WriteDecimalArray";
605 writeArrayMethod = "WriteInt32Array";
608 writeArrayMethod = "WriteInt64Array";
610 case TypeCode.Single:
611 writeArrayMethod = "WriteSingleArray";
613 case TypeCode.Double:
614 writeArrayMethod = "WriteDoubleArray";
619 if (writeArrayMethod != null)
621 ilg.Load(xmlWriterArg);
624 ilg.Load(itemNamespace);
625 ilg.Call(typeof(XmlWriterDelegator).GetMethod(writeArrayMethod, Globals.ScanAllMembers, null, new Type[] { type, typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null));
631 void WriteValue(LocalBuilder memberValue, bool writeXsiType)
633 Type memberType = memberValue.LocalType;
634 if (memberType.IsPointer)
636 ilg.Load(memberValue);
637 ilg.Load(memberType);
638 ilg.Call(XmlFormatGeneratorStatics.BoxPointer);
639 memberType = Globals.TypeOfReflectionPointer;
640 memberValue = ilg.DeclareLocal(memberType, "memberValueRefPointer");
641 ilg.Store(memberValue);
643 bool isNullableOfT = (memberType.IsGenericType &&
644 memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable);
645 if (memberType.IsValueType && !isNullableOfT)
647 PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
648 if (primitiveContract != null && !writeXsiType)
649 ilg.Call(xmlWriterArg, primitiveContract.XmlFormatContentWriterMethod, memberValue);
651 InternalSerialize(XmlFormatGeneratorStatics.InternalSerializeMethod, memberValue, memberType, writeXsiType);
657 memberValue = UnwrapNullableObject(memberValue); //Leaves !HasValue on stack
658 memberType = memberValue.LocalType;
662 ilg.Load(memberValue);
667 ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteNullMethod, xmlWriterArg, memberType, DataContract.IsTypeSerializable(memberType));
669 PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
670 if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject && !writeXsiType)
674 ilg.Call(xmlWriterArg, primitiveContract.XmlFormatContentWriterMethod, memberValue);
678 ilg.Call(contextArg, primitiveContract.XmlFormatContentWriterMethod, xmlWriterArg, memberValue);
683 if (memberType == Globals.TypeOfObject || //boxed Nullable<T>
684 memberType == Globals.TypeOfValueType ||
685 ((IList)Globals.TypeOfNullable.GetInterfaces()).Contains(memberType))
687 ilg.Load(memberValue);
688 ilg.ConvertValue(memberValue.LocalType, Globals.TypeOfObject);
689 memberValue = ilg.DeclareLocal(Globals.TypeOfObject, "unwrappedMemberValue");
690 memberType = memberValue.LocalType;
691 ilg.Stloc(memberValue);
692 ilg.If(memberValue, Cmp.EqualTo, null);
693 ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteNullMethod, xmlWriterArg, memberType, DataContract.IsTypeSerializable(memberType));
696 InternalSerialize((isNullableOfT ? XmlFormatGeneratorStatics.InternalSerializeMethod : XmlFormatGeneratorStatics.InternalSerializeReferenceMethod),
697 memberValue, memberType, writeXsiType);
699 if (memberType == Globals.TypeOfObject) //boxed Nullable<T>
706 void InternalSerialize(MethodInfo methodInfo, LocalBuilder memberValue, Type memberType, bool writeXsiType)
708 ilg.Load(contextArg);
709 ilg.Load(xmlWriterArg);
710 ilg.Load(memberValue);
711 ilg.ConvertValue(memberValue.LocalType, Globals.TypeOfObject);
712 LocalBuilder typeHandleValue = ilg.DeclareLocal(typeof(RuntimeTypeHandle), "typeHandleValue");
713 ilg.Call(null, typeof(Type).GetMethod("GetTypeHandle"), memberValue);
714 ilg.Stloc(typeHandleValue);
715 ilg.LoadAddress(typeHandleValue);
716 ilg.Ldtoken(memberType);
717 ilg.Call(typeof(RuntimeTypeHandle).GetMethod("Equals", new Type[] { typeof(RuntimeTypeHandle) }));
718 ilg.Load(writeXsiType);
719 ilg.Load(DataContract.GetId(memberType.TypeHandle));
720 ilg.Ldtoken(memberType);
721 ilg.Call(methodInfo);
725 LocalBuilder UnwrapNullableObject(LocalBuilder memberValue)// Leaves !HasValue on stack
727 Type memberType = memberValue.LocalType;
728 Label onNull = ilg.DefineLabel();
729 Label end = ilg.DefineLabel();
730 ilg.Load(memberValue);
731 while (memberType.IsGenericType && memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable)
733 Type innerType = memberType.GetGenericArguments()[0];
735 ilg.Call(XmlFormatGeneratorStatics.GetHasValueMethod.MakeGenericMethod(innerType));
737 ilg.Call(XmlFormatGeneratorStatics.GetNullableValueMethod.MakeGenericMethod(innerType));
738 memberType = innerType;
740 memberValue = ilg.DeclareLocal(memberType, "nullableUnwrappedMemberValue");
741 ilg.Stloc(memberValue);
742 ilg.Load(false); //isNull
744 ilg.MarkLabel(onNull);
746 ilg.Call(XmlFormatGeneratorStatics.GetDefaultValueMethod.MakeGenericMethod(memberType));
747 ilg.Stloc(memberValue);
748 ilg.Load(true); //isNull
753 bool NeedsPrefix(Type type, XmlDictionaryString ns)
755 return type == Globals.TypeOfXmlQualifiedName && (ns != null && ns.Value != null && ns.Value.Length > 0);
758 void WriteStartElement(Type type, XmlDictionaryString ns, LocalBuilder namespaceLocal, LocalBuilder nameLocal, int nameIndex)
760 bool needsPrefix = NeedsPrefix(type, ns);
761 ilg.Load(xmlWriterArg);
764 ilg.Load(Globals.ElementPrefix);
767 if (nameLocal == null)
768 ilg.LoadArrayElement(memberNamesLocal, nameIndex);
773 ilg.Load(namespaceLocal);
775 ilg.Call(needsPrefix ? XmlFormatGeneratorStatics.WriteStartElementMethod3 : XmlFormatGeneratorStatics.WriteStartElementMethod2);
778 void WriteEndElement()
780 ilg.Call(xmlWriterArg, XmlFormatGeneratorStatics.WriteEndElementMethod);
783 bool CheckIfMemberHasConflict(DataMember member, ClassDataContract classContract, ClassDataContract derivedMostClassContract)
785 // Check for conflict with base type members
786 if (CheckIfConflictingMembersHaveDifferentTypes(member))
789 // Check for conflict with derived type members
790 string name = member.Name;
791 string ns = classContract.StableName.Namespace;
792 ClassDataContract currentContract = derivedMostClassContract;
793 while (currentContract != null && currentContract != classContract)
795 if (ns == currentContract.StableName.Namespace)
797 List<DataMember> members = currentContract.Members;
798 for (int j = 0; j < members.Count; j++)
800 if (name == members[j].Name)
801 return CheckIfConflictingMembersHaveDifferentTypes(members[j]);
804 currentContract = currentContract.BaseContract;
810 bool CheckIfConflictingMembersHaveDifferentTypes(DataMember member)
812 while (member.ConflictingMember != null)
814 if (member.MemberType != member.ConflictingMember.MemberType)
816 member = member.ConflictingMember;
822 static Hashtable nsToPrefixTable = new Hashtable(4);
823 internal static string GetPrefix(string ns)
825 string prefix = (string)nsToPrefixTable[ns];
828 lock (nsToPrefixTable)
832 prefix = "p" + nsToPrefixTable.Count;
833 nsToPrefixTable.Add(ns, prefix);