[sgen] Clear the card table in the finishing pause
[mono.git] / mcs / class / System.Runtime.Serialization / ReferenceSources / XmlFormatWriterGenerator_static.cs
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Reflection;
6 using System.Xml;
7
8 namespace System.Runtime.Serialization
9 {
10         internal partial class XmlFormatWriterGenerator
11         {
12                 partial class CriticalHelper
13                 {
14                         internal XmlFormatClassWriterDelegate GenerateClassWriter(ClassDataContract classContract)
15                         {
16                                 return (XmlWriterDelegator xw, object obj, XmlObjectSerializerWriteContext ctx, ClassDataContract ctr) => new XmlFormatWriterInterpreter (classContract).WriteToXml (xw, obj, ctx, ctr);
17                         }
18
19                         internal XmlFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionDataContract collectionContract)
20                         {
21                                 return (XmlWriterDelegator xw, object obj, XmlObjectSerializerWriteContext ctx, CollectionDataContract ctr) => new XmlFormatWriterInterpreter (collectionContract).WriteCollectionToXml (xw, obj, ctx, ctr);
22                         }
23                 }
24         }
25
26         class XmlFormatWriterInterpreter
27         {
28                 public XmlFormatWriterInterpreter (ClassDataContract classContract)
29                 {
30                         this.classContract = classContract;
31                 }
32
33                 public XmlFormatWriterInterpreter (CollectionDataContract collectionContract)
34                 {
35                         this.collectionContract = collectionContract;
36                 }
37
38                 ClassDataContract classContract;
39
40                 CollectionDataContract collectionContract;
41
42                 XmlWriterDelegator writer = null;
43                 object obj = null;
44                 XmlObjectSerializerWriteContext ctx = null;
45                 DataContract dataContract = null;
46                 object objLocal = null;
47
48                 ClassDataContract classDataContract {
49                         get { return (ClassDataContract) dataContract; }
50                 }
51                 CollectionDataContract collectionDataContract {
52                         get {return (CollectionDataContract) dataContract; }
53                 }
54
55                 XmlDictionaryString [] contractNamespaces = null;
56                 XmlDictionaryString [] memberNames = null;
57                 XmlDictionaryString [] childElementNamespaces = null;
58                 int typeIndex = 1;
59                 int childElementIndex = 0;
60
61                 public void WriteToXml (XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, ClassDataContract dataContract)
62                 {
63                         this.writer = xmlWriter;
64                         this.obj = obj;
65                         this.ctx = context;
66                         this.dataContract = dataContract;
67
68                         InitArgs (classContract.UnderlyingType);
69
70                         // DemandSerializationFormatterPermission (classContract) - irrelevant
71                         // DemandMemberAccessPermission (memberAccessFlag) - irrelevant
72
73                         if (classContract.IsReadOnlyContract)
74                         {
75                                 DataContract.ThrowInvalidDataContractException (classContract.SerializationExceptionMessage, null);
76                         }
77
78                         WriteClass (classContract);
79                 }
80
81                 public void WriteCollectionToXml (XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, CollectionDataContract collectionContract)
82                 {
83                         this.writer = xmlWriter;
84                         this.obj = obj;
85                         this.ctx = context;
86                         this.dataContract = collectionContract;
87
88                         InitArgs (collectionContract.UnderlyingType);                   
89
90                         // DemandMemberAccessPermission(memberAccessFlag);
91                         if (collectionContract.IsReadOnlyContract)
92                         {
93                                 DataContract.ThrowInvalidDataContractException (collectionContract.SerializationExceptionMessage, null);
94                         }
95
96                         WriteCollection (collectionContract);
97                 }
98
99                 void InitArgs (Type objType)
100                 {
101                         if (objType == Globals.TypeOfDateTimeOffsetAdapter) {
102                                 objLocal = DateTimeOffsetAdapter.GetDateTimeOffsetAdapter ((DateTimeOffset) obj);
103                         }
104                         else
105                                 objLocal = CodeInterpreter.ConvertValue (obj, typeof (object), objType);
106                 }
107
108                 void InvokeOnSerializing (ClassDataContract classContract, object objSerialized, XmlObjectSerializerWriteContext ctx)
109                 {
110                         if (classContract.BaseContract != null)
111                                 InvokeOnSerializing (classContract.BaseContract, objSerialized, ctx);
112                         if (classContract.OnSerializing != null) {
113                                 classContract.OnSerializing.Invoke (objSerialized, new object [] {ctx.GetStreamingContext ()});
114                         }
115                 }
116
117                 void InvokeOnSerialized (ClassDataContract classContract, object objSerialized, XmlObjectSerializerWriteContext ctx)
118                 {
119                         if (classContract.BaseContract != null)
120                                 InvokeOnSerialized (classContract.BaseContract, objSerialized, ctx);
121                         if (classContract.OnSerialized != null) {
122                                 classContract.OnSerialized.Invoke (objSerialized, new object [] {ctx.GetStreamingContext ()});
123                         }
124                 }
125
126                 void WriteClass (ClassDataContract classContract)
127                 {
128                         InvokeOnSerializing (classContract, objLocal, ctx);
129
130                         if (classContract.IsISerializable)
131                                 ctx.WriteISerializable (writer, (ISerializable) objLocal);
132                         else
133                         {
134                                 if (classContract.ContractNamespaces.Length > 1)
135                                         contractNamespaces = classDataContract.ContractNamespaces;
136                                 memberNames = classDataContract.MemberNames;
137
138                                 for (int i = 0; i < classContract.ChildElementNamespaces.Length; i++)
139                                 {
140                                         if (classContract.ChildElementNamespaces[i] != null)
141                                         {
142                                                 childElementNamespaces = classDataContract.ChildElementNamespaces;
143                                         }
144                                 }
145
146                                 if (classContract.HasExtensionData)
147                                 {
148                                         ExtensionDataObject extensionData = ((IExtensibleDataObject) objLocal).ExtensionData;
149                                         ctx.WriteExtensionData (writer, extensionData, -1);
150
151                                         WriteMembers (classContract, extensionData, classContract);
152                                 }
153                                 else
154                                         WriteMembers (classContract, null, classContract);
155                         }
156                         InvokeOnSerialized (classContract, objLocal, ctx);
157                 }
158
159                 void WriteCollection(CollectionDataContract collectionContract)
160                 {
161                         XmlDictionaryString itemNamespace = dataContract.Namespace;
162
163                         XmlDictionaryString itemName = collectionDataContract.CollectionItemName;
164
165                         if (collectionContract.ChildElementNamespace != null)
166                                 writer.WriteNamespaceDecl (collectionDataContract.ChildElementNamespace);
167
168                         if (collectionContract.Kind == CollectionKind.Array)
169                         {
170                                 Type itemType = collectionContract.ItemType;
171                                 int i;
172
173                                 // This check does not exist in the original dynamic code,
174                                 // but there is no other way to check type mismatch.
175                                 // CollectionSerialization.ArrayContract() shows that it is required.
176                                 if (objLocal.GetType ().GetElementType () != itemType)
177                                         throw new InvalidCastException (string.Format ("Cannot cast array of {0} to array of {1}", objLocal.GetType ().GetElementType (), itemType));
178
179                                 ctx.IncrementArrayCount (writer, (Array) objLocal);
180
181                                 if (!TryWritePrimitiveArray(collectionContract.UnderlyingType, itemType, () => objLocal, itemName, itemNamespace))
182                                 {
183                                         var arr = (Array) objLocal;
184                                         var idx = new int [1];
185                                         for (i = 0; i < arr.Length; i++) {
186                                                 if (!TryWritePrimitive(itemType, null, null, i, itemNamespace, itemName, 0)) {
187                                                         WriteStartElement (itemType, collectionContract.Namespace, itemNamespace, itemName, 0);
188                                                         idx [0] = i;
189                                                         var mbrVal = arr.GetValue (idx);
190                                                         WriteValue (itemType, mbrVal, false);
191                                                         WriteEndElement ();
192                                                 }
193                                         }
194                                 }
195                         }
196                         else
197                         {
198                                 // This check does not exist in the original dynamic code,
199                                 // but there is no other way to check type mismatch.
200                                 // CollectionSerialization.ArrayContract() shows that it is required.
201                                 if (!collectionContract.UnderlyingType.IsAssignableFrom (objLocal.GetType ()))
202                                         throw new InvalidCastException (string.Format ("Cannot cast {0} to {1}", objLocal.GetType (), collectionContract.UnderlyingType));
203                                 
204                                 MethodInfo incrementCollectionCountMethod = null;
205                                 switch (collectionContract.Kind)
206                                 {
207                                 case CollectionKind.Collection:
208                                 case CollectionKind.List:
209                                 case CollectionKind.Dictionary:
210                                         incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountMethod;
211                                         break;
212                                 case CollectionKind.GenericCollection:
213                                 case CollectionKind.GenericList:
214                                         incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(collectionContract.ItemType);
215                                         break;
216                                 case CollectionKind.GenericDictionary:
217                                         incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments()));
218                                         break;
219                                 }
220                                 if (incrementCollectionCountMethod != null)
221                                         incrementCollectionCountMethod.Invoke (ctx, new object [] {writer, objLocal});
222
223                                 bool isDictionary = false, isGenericDictionary = false;
224                                 Type enumeratorType = null;
225                                 Type [] keyValueTypes = null;
226                                 if (collectionContract.Kind == CollectionKind.GenericDictionary)
227                                 {
228                                         isGenericDictionary = true;
229                                         keyValueTypes = collectionContract.ItemType.GetGenericArguments ();
230                                         enumeratorType = Globals.TypeOfGenericDictionaryEnumerator.MakeGenericType (keyValueTypes);
231                                 }
232                                 else if (collectionContract.Kind == CollectionKind.Dictionary)
233                                 {
234                                         isDictionary = true;
235                                         keyValueTypes = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
236                                         enumeratorType = Globals.TypeOfDictionaryEnumerator;
237                                 }
238                                 else
239                                 {
240                                         enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType;
241                                 }
242                                 MethodInfo moveNextMethod = enumeratorType.GetMethod (Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
243                                 MethodInfo getCurrentMethod = enumeratorType.GetMethod (Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
244                                 if (moveNextMethod == null || getCurrentMethod == null)
245                                 {
246                                         if (enumeratorType.IsInterface)
247                                         {
248                                                 if (moveNextMethod == null)
249                                                         moveNextMethod = XmlFormatGeneratorStatics.MoveNextMethod;
250                                                 if (getCurrentMethod == null)
251                                                         getCurrentMethod = XmlFormatGeneratorStatics.GetCurrentMethod;
252                                         }
253                                         else
254                                         {
255                                                 Type ienumeratorInterface = Globals.TypeOfIEnumerator;
256                                                 CollectionKind kind = collectionContract.Kind;
257                                                 if (kind == CollectionKind.GenericDictionary || kind == CollectionKind.GenericCollection || kind == CollectionKind.GenericEnumerable)
258                                                 {
259                                                         Type[] interfaceTypes = enumeratorType.GetInterfaces();
260                                                         foreach (Type interfaceType in interfaceTypes)
261                                                         {
262                                                                 if (interfaceType.IsGenericType
263                                                                         && interfaceType.GetGenericTypeDefinition() == Globals.TypeOfIEnumeratorGeneric
264                                                                         && interfaceType.GetGenericArguments()[0] == collectionContract.ItemType)
265                                                                 {
266                                                                         ienumeratorInterface = interfaceType;
267                                                                         break;
268                                                                 }
269                                                         }
270                                                 }
271                                                 if (moveNextMethod == null)
272                                                         moveNextMethod = CollectionDataContract.GetTargetMethodWithName(Globals.MoveNextMethodName, enumeratorType, ienumeratorInterface);
273                                                 if (getCurrentMethod == null)
274                                                         getCurrentMethod = CollectionDataContract.GetTargetMethodWithName(Globals.GetCurrentMethodName, enumeratorType, ienumeratorInterface);
275                                         }
276                                 }
277                                 Type elementType = getCurrentMethod.ReturnType;
278                                 object currentValue = null; // of elementType
279
280                                 var enumerator = (IEnumerator) collectionContract.GetEnumeratorMethod.Invoke (objLocal, new object [0]);
281                                 if (isDictionary)
282                                 {
283                                         enumerator = new CollectionDataContract.DictionaryEnumerator ((IDictionaryEnumerator) enumerator);
284                                 }
285                                 else if (isGenericDictionary)
286                                 {
287                                         Type ctorParam = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes));
288                                         ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { ctorParam }, null);
289                                         enumerator = (IEnumerator) Activator.CreateInstance (enumeratorType, new object [] {enumerator});
290                                 }
291
292                                 var emptyArray = new object [0];
293                                 while (enumerator != null && enumerator.MoveNext ()) {
294                                         currentValue = getCurrentMethod.Invoke (enumerator, emptyArray);
295
296                                         if (incrementCollectionCountMethod == null)
297                                                 XmlFormatGeneratorStatics.IncrementItemCountMethod.Invoke (ctx, new object [] {1});
298
299                                         if (!TryWritePrimitive (elementType, () => currentValue, null, null, itemNamespace, itemName, 0))
300                                         {
301                                                 WriteStartElement (elementType, collectionContract.Namespace, itemNamespace, itemName, 0);
302                                                 if (isGenericDictionary || isDictionary)
303                                                         collectionDataContract.ItemContract.WriteXmlValue (writer, currentValue, ctx);
304                                                 else
305                                                         WriteValue (elementType, currentValue, false);
306                                                 WriteEndElement();
307                                         }
308                                 }
309                         }
310                 }
311
312                 int WriteMembers (ClassDataContract classContract, ExtensionDataObject extensionData, ClassDataContract derivedMostClassContract)
313                 {
314                         int memberCount = (classContract.BaseContract == null) ? 0 : WriteMembers (classContract.BaseContract, extensionData, derivedMostClassContract);
315
316                         XmlDictionaryString ns = 
317                                 (contractNamespaces == null) ? dataContract.Namespace :
318                                 contractNamespaces [typeIndex - 1];
319
320                         ctx.IncrementItemCount (classContract.Members.Count);
321
322                         for (int i = 0; i < classContract.Members.Count; i++, memberCount++) {
323
324                                 DataMember member = classContract.Members[i];
325                                 Type memberType = member.MemberType;
326                                 object memberValue = null;
327                                 if (member.IsGetOnlyCollection)
328                                         ctx.StoreIsGetOnlyCollection ();
329                                 bool doWrite = true, hasMemberValue = false;
330                                 if (!member.EmitDefaultValue)
331                                 {
332                                         hasMemberValue = true;
333                                         memberValue = LoadMemberValue (member);
334                                         doWrite = !IsDefaultValue (memberType, memberValue);
335                                 }
336
337                                 if (doWrite) {
338
339                                         bool writeXsiType = CheckIfMemberHasConflict (member, classContract, derivedMostClassContract);
340                                         if (writeXsiType || !TryWritePrimitive (memberType, hasMemberValue ? () => memberValue : (Func<object>) null, member.MemberInfo, null /*arrayItemIndex*/, ns, null /*nameLocal*/, i + childElementIndex)) {
341                                                 WriteStartElement (memberType, classContract.Namespace, ns, null /*nameLocal*/, i + childElementIndex);
342                                                 if (classContract.ChildElementNamespaces [i + childElementIndex] != null)
343                                                         writer.WriteNamespaceDecl (childElementNamespaces [i + childElementIndex]);
344                                                 if (memberValue == null)
345                                                         memberValue = LoadMemberValue (member);
346                                                 WriteValue (memberType, memberValue, writeXsiType);
347                                                 WriteEndElement ();
348                                         }
349
350                                         if (classContract.HasExtensionData)
351                                                 ctx.WriteExtensionData (writer, extensionData, memberCount);
352                                 } else if (!member.EmitDefaultValue) {
353                                         if (member.IsRequired)
354                                                 XmlObjectSerializerWriteContext.ThrowRequiredMemberMustBeEmitted (member.Name, classContract.UnderlyingType);
355                                 }
356                         }
357
358                         typeIndex++;
359                         childElementIndex += classContract.Members.Count;
360                         return memberCount;
361                 }
362
363
364                 internal bool IsDefaultValue (Type type, object value)
365                 {
366                         var def = GetDefaultValue (type);
367                         return def == null ? (object) value == null : def.Equals (value);
368                 }
369
370                 internal object GetDefaultValue(Type type)
371                 {
372                         if (type.IsValueType)
373                         {
374                                 switch (Type.GetTypeCode(type))
375                                 {
376                                 case TypeCode.Boolean:
377                                         return false;
378                                 case TypeCode.Char:
379                                 case TypeCode.SByte:
380                                 case TypeCode.Byte:
381                                 case TypeCode.Int16:
382                                 case TypeCode.UInt16:
383                                 case TypeCode.Int32:
384                                 case TypeCode.UInt32:
385                                         return 0;
386                                 case TypeCode.Int64:
387                                 case TypeCode.UInt64:
388                                         return 0L;
389                                 case TypeCode.Single:
390                                         return 0.0F;
391                                 case TypeCode.Double:
392                                         return 0.0;
393                                 case TypeCode.Decimal:
394                                         return default (decimal);
395                                 case TypeCode.DateTime:
396                                         return default (DateTime);
397                                 }
398                         }
399                         return null;
400                 }
401
402                 bool CheckIfMemberHasConflict(DataMember member, ClassDataContract classContract, ClassDataContract derivedMostClassContract)
403                 {
404                         // Check for conflict with base type members
405                         if (CheckIfConflictingMembersHaveDifferentTypes(member))
406                                 return true;
407
408                         // Check for conflict with derived type members
409                         string name = member.Name;
410                         string ns = classContract.StableName.Namespace;
411                         ClassDataContract currentContract = derivedMostClassContract;
412                         while (currentContract != null && currentContract != classContract)
413                         {
414                                 if (ns == currentContract.StableName.Namespace)
415                                 {
416                                         List<DataMember> members = currentContract.Members;
417                                         for (int j = 0; j < members.Count; j++)
418                                         {
419                                                 if (name == members[j].Name)
420                                                         return CheckIfConflictingMembersHaveDifferentTypes(members[j]);
421                                         }
422                                 }
423                                 currentContract = currentContract.BaseContract;
424                         }
425
426                         return false;
427                 }
428
429                 bool CheckIfConflictingMembersHaveDifferentTypes(DataMember member)
430                 {
431                         while (member.ConflictingMember != null)
432                         {
433                                 if (member.MemberType != member.ConflictingMember.MemberType)
434                                         return true;
435                                 member = member.ConflictingMember;
436                         }
437                         return false;
438                 }
439
440                 bool NeedsPrefix(Type type, XmlDictionaryString ns)
441                 {
442                         return type == Globals.TypeOfXmlQualifiedName && (ns != null && ns.Value != null && ns.Value.Length > 0);
443                 }
444
445                 void WriteStartElement (Type type, XmlDictionaryString ns, XmlDictionaryString namespaceLocal, XmlDictionaryString nameLocal, int nameIndex)
446                 {
447                         bool needsPrefix = NeedsPrefix(type, ns);
448                         nameLocal = nameLocal ?? memberNames [nameIndex];
449                         if (needsPrefix)
450                                 writer.WriteStartElement (Globals.ElementPrefix, nameLocal, namespaceLocal);
451                         else
452                                 writer.WriteStartElement (nameLocal, namespaceLocal);
453                 }
454
455                 void WriteEndElement ()
456                 {
457                         writer.WriteEndElement ();
458                 }
459
460                 void WriteValue (Type memberType, object memberValue, bool writeXsiType)
461                 {
462                         Pointer memberValueRefPointer = null;
463                         if (memberType.IsPointer)
464                                 memberValueRefPointer = (Pointer) XmlFormatGeneratorStatics.BoxPointer.Invoke (null, new object [] {memberValue, memberType});
465                         bool isNullableOfT = (memberType.IsGenericType &&
466                                 memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable);
467                         if (memberType.IsValueType && !isNullableOfT)
468                         {
469                                 PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
470                                 if (primitiveContract != null && !writeXsiType)
471                                         primitiveContract.XmlFormatContentWriterMethod.Invoke (writer, new object [] {memberValue});
472                                 else {
473                                         // InternalSerialize(XmlFormatGeneratorStatics.InternalSerializeMethod, () => memberValue, memberType, writeXsiType);
474                                         var typeHandleValue = Type.GetTypeHandle (memberValue);
475                                         var isDeclaredType = typeHandleValue.Equals (CodeInterpreter.ConvertValue (memberValue, memberType, Globals.TypeOfObject));
476                                         
477                                         ctx.InternalSerialize (writer, memberValue, isDeclaredType, writeXsiType, DataContract.GetId (memberType.TypeHandle), memberType.TypeHandle);
478                                 }
479                         }
480                         else
481                         {
482                                 bool isNull;
483                                 if (isNullableOfT)
484                                         memberValue = UnwrapNullableObject(() => memberValue, ref memberType, out isNull); //Leaves !HasValue on stack
485                                 else
486                                         isNull = memberValue == null;
487                                 if (isNull)
488                                         XmlFormatGeneratorStatics.WriteNullMethod.Invoke (ctx, new object [] {writer, memberType, DataContract.IsTypeSerializable(memberType)});
489                                 else {
490                                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
491                                         if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject && !writeXsiType) {
492                                                 if (isNullableOfT)
493                                                         primitiveContract.XmlFormatContentWriterMethod.Invoke (writer, new object [] {memberValue});
494                                                 else                                                    
495                                                         primitiveContract.XmlFormatContentWriterMethod.Invoke (ctx, new object [] {writer, memberValue});
496                                         } else {
497                                                 bool isNull2 = false;
498                                                 if (memberType == Globals.TypeOfObject || //boxed Nullable<T>
499                                                         memberType == Globals.TypeOfValueType ||
500                                                         ((IList)Globals.TypeOfNullable.GetInterfaces()).Contains(memberType)) {
501                                                         var unwrappedMemberValue = CodeInterpreter.ConvertValue (memberValue, memberType.GetType (), Globals.TypeOfObject);
502                                                         memberValue = unwrappedMemberValue;
503                                                         isNull2 = memberValue == null;
504                                                 }
505                                                 if (isNull2) {
506                                                         XmlFormatGeneratorStatics.WriteNullMethod.Invoke (ctx, new object [] {writer, memberType, DataContract.IsTypeSerializable(memberType)});
507                                                 } else {
508                                                         var typeHandleValue = Type.GetTypeHandle (memberValue);
509                                                         var isDeclaredType = typeHandleValue.Equals (CodeInterpreter.ConvertValue (memberValue, memberType, Globals.TypeOfObject));
510                                                         if (isNullableOfT)
511                                                                 ctx.InternalSerialize (writer, memberValue, isDeclaredType, writeXsiType, DataContract.GetId (memberType.TypeHandle), memberType.TypeHandle);
512                                                         else
513                                                                 ctx.InternalSerializeReference (writer, memberValue, isDeclaredType, writeXsiType, DataContract.GetId (memberType.TypeHandle), memberType.TypeHandle);                                                          
514                                                         //InternalSerialize((isNullableOfT ? XmlFormatGeneratorStatics.InternalSerializeMethod : XmlFormatGeneratorStatics.InternalSerializeReferenceMethod), () => memberValue, memberType, writeXsiType);
515                                                 }
516                                         }
517                                 }
518                         }
519                 }
520
521                 object UnwrapNullableObject(Func<object> memberValue, ref Type memberType, out bool isNull)// Leaves !HasValue on stack
522                 {
523                         object v = memberValue ();
524                         isNull = false;
525                         while (memberType.IsGenericType && memberType.GetGenericTypeDefinition () == Globals.TypeOfNullable) {
526                                 Type innerType = memberType.GetGenericArguments () [0];
527                                 if ((bool) XmlFormatGeneratorStatics.GetHasValueMethod.MakeGenericMethod (innerType).Invoke (null, new object [] {v}))
528                                         v = XmlFormatGeneratorStatics.GetNullableValueMethod.MakeGenericMethod (innerType).Invoke (null, new object [] {v});
529                                 else {
530                                         isNull = true;
531                                         v = XmlFormatGeneratorStatics.GetDefaultValueMethod.MakeGenericMethod (memberType).Invoke (null, new object [0]);
532                                 }
533                                 memberType = innerType;
534                         }
535                         
536                         return v;
537                 }
538
539                 bool TryWritePrimitive(Type type, Func<object> value, MemberInfo memberInfo, int? arrayItemIndex, XmlDictionaryString ns, XmlDictionaryString name, int nameIndex)
540                 {
541                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);
542                         if (primitiveContract == null || primitiveContract.UnderlyingType == Globals.TypeOfObject)
543                                 return false;
544
545                         object callee = null;
546                         var args = new List<object> ();
547
548                         // load xmlwriter
549                         if (type.IsValueType)
550                                 callee = writer;
551                         else {
552                                 callee = ctx;
553                                 args.Add (writer);
554                         }
555                         // load primitive value 
556                         if (value != null)
557                                 args.Add (value ());
558                         else if (memberInfo != null)
559                                 args.Add (CodeInterpreter.GetMember (memberInfo, objLocal));
560                         else
561                                 args.Add (((Array) objLocal).GetValue (new int [] {(int) arrayItemIndex}));
562                         // load name
563                         if (name != null)
564                                 args.Add (name);
565                         else
566                                 args.Add (memberNames [nameIndex]);
567                         // load namespace
568                         args.Add (ns);
569                         // call method to write primitive
570                         primitiveContract.XmlFormatWriterMethod.Invoke (callee, args.ToArray ());
571                         return true;
572                 }
573
574                 bool TryWritePrimitiveArray (Type type, Type itemType, Func<object> value, XmlDictionaryString itemName, XmlDictionaryString itemNamespace)
575                 {
576                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType);
577                         if (primitiveContract == null)
578                                 return false;
579
580                         string writeArrayMethod = null;
581                         switch (Type.GetTypeCode(itemType))
582                         {
583                         case TypeCode.Boolean:
584                                 writeArrayMethod = "WriteBooleanArray";
585                                 break;
586                         case TypeCode.DateTime:
587                                 writeArrayMethod = "WriteDateTimeArray";
588                                 break;
589                         case TypeCode.Decimal:
590                                 writeArrayMethod = "WriteDecimalArray";
591                                 break;
592                         case TypeCode.Int32:
593                                 writeArrayMethod = "WriteInt32Array";
594                                 break;
595                         case TypeCode.Int64:
596                                 writeArrayMethod = "WriteInt64Array";
597                                 break;
598                         case TypeCode.Single:
599                                 writeArrayMethod = "WriteSingleArray";
600                                 break;
601                         case TypeCode.Double:
602                                 writeArrayMethod = "WriteDoubleArray";
603                                 break;
604                         default:
605                                 break;
606                         }
607                         if (writeArrayMethod != null)
608                         {
609                                 typeof (XmlWriterDelegator).GetMethod (writeArrayMethod, Globals.ScanAllMembers, null, new Type[] { type, typeof (XmlDictionaryString), typeof (XmlDictionaryString) }, null).Invoke (writer, new object [] {value (), itemName, itemNamespace});
610                                 return true;
611                         }
612                         return false;
613                 }
614
615                 object LoadMemberValue (DataMember member)
616                 {
617                         return CodeInterpreter.GetMember (member.MemberInfo, objLocal);
618                 }
619         }
620 }