Merge pull request #1668 from alexanderkyte/bug1856
[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                         return GetDefaultValue (type).Equals (value);
367                 }
368
369                 internal object GetDefaultValue(Type type)
370                 {
371                         if (type.IsValueType)
372                         {
373                                 switch (Type.GetTypeCode(type))
374                                 {
375                                 case TypeCode.Boolean:
376                                         return false;
377                                 case TypeCode.Char:
378                                 case TypeCode.SByte:
379                                 case TypeCode.Byte:
380                                 case TypeCode.Int16:
381                                 case TypeCode.UInt16:
382                                 case TypeCode.Int32:
383                                 case TypeCode.UInt32:
384                                         return 0;
385                                 case TypeCode.Int64:
386                                 case TypeCode.UInt64:
387                                         return 0L;
388                                 case TypeCode.Single:
389                                         return 0.0F;
390                                 case TypeCode.Double:
391                                         return 0.0;
392                                 case TypeCode.Decimal:
393                                         return default (decimal);
394                                 case TypeCode.DateTime:
395                                         return default (DateTime);
396                                 }
397                         }
398                         return null;
399                 }
400
401                 bool CheckIfMemberHasConflict(DataMember member, ClassDataContract classContract, ClassDataContract derivedMostClassContract)
402                 {
403                         // Check for conflict with base type members
404                         if (CheckIfConflictingMembersHaveDifferentTypes(member))
405                                 return true;
406
407                         // Check for conflict with derived type members
408                         string name = member.Name;
409                         string ns = classContract.StableName.Namespace;
410                         ClassDataContract currentContract = derivedMostClassContract;
411                         while (currentContract != null && currentContract != classContract)
412                         {
413                                 if (ns == currentContract.StableName.Namespace)
414                                 {
415                                         List<DataMember> members = currentContract.Members;
416                                         for (int j = 0; j < members.Count; j++)
417                                         {
418                                                 if (name == members[j].Name)
419                                                         return CheckIfConflictingMembersHaveDifferentTypes(members[j]);
420                                         }
421                                 }
422                                 currentContract = currentContract.BaseContract;
423                         }
424
425                         return false;
426                 }
427
428                 bool CheckIfConflictingMembersHaveDifferentTypes(DataMember member)
429                 {
430                         while (member.ConflictingMember != null)
431                         {
432                                 if (member.MemberType != member.ConflictingMember.MemberType)
433                                         return true;
434                                 member = member.ConflictingMember;
435                         }
436                         return false;
437                 }
438
439                 bool NeedsPrefix(Type type, XmlDictionaryString ns)
440                 {
441                         return type == Globals.TypeOfXmlQualifiedName && (ns != null && ns.Value != null && ns.Value.Length > 0);
442                 }
443
444                 void WriteStartElement (Type type, XmlDictionaryString ns, XmlDictionaryString namespaceLocal, XmlDictionaryString nameLocal, int nameIndex)
445                 {
446                         bool needsPrefix = NeedsPrefix(type, ns);
447                         nameLocal = nameLocal ?? memberNames [nameIndex];
448                         if (needsPrefix)
449                                 writer.WriteStartElement (Globals.ElementPrefix, nameLocal, namespaceLocal);
450                         else
451                                 writer.WriteStartElement (nameLocal, namespaceLocal);
452                 }
453
454                 void WriteEndElement ()
455                 {
456                         writer.WriteEndElement ();
457                 }
458
459                 void WriteValue (Type memberType, object memberValue, bool writeXsiType)
460                 {
461                         Pointer memberValueRefPointer = null;
462                         if (memberType.IsPointer)
463                                 memberValueRefPointer = (Pointer) XmlFormatGeneratorStatics.BoxPointer.Invoke (null, new object [] {memberValue, memberType});
464                         bool isNullableOfT = (memberType.IsGenericType &&
465                                 memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable);
466                         if (memberType.IsValueType && !isNullableOfT)
467                         {
468                                 PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
469                                 if (primitiveContract != null && !writeXsiType)
470                                         primitiveContract.XmlFormatContentWriterMethod.Invoke (writer, new object [] {memberValue});
471                                 else
472                                         InternalSerialize(XmlFormatGeneratorStatics.InternalSerializeMethod, () => memberValue, memberType, writeXsiType);
473                         }
474                         else
475                         {
476                                 bool isNull;
477                                 if (isNullableOfT)
478                                         memberValue = UnwrapNullableObject(() => memberValue, ref memberType, out isNull); //Leaves !HasValue on stack
479                                 else
480                                         isNull = memberValue == null;
481                                 if (isNull)
482                                         XmlFormatGeneratorStatics.WriteNullMethod.Invoke (ctx, new object [] {writer, memberType, DataContract.IsTypeSerializable(memberType)});
483                                 else {
484                                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
485                                         if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject && !writeXsiType) {
486                                                 if (isNullableOfT)
487                                                         primitiveContract.XmlFormatContentWriterMethod.Invoke (writer, new object [] {memberValue});
488                                                 else                                                    
489                                                         primitiveContract.XmlFormatContentWriterMethod.Invoke (ctx, new object [] {writer, memberValue});
490                                         } else {
491                                                 bool isNull2 = false;
492                                                 if (memberType == Globals.TypeOfObject || //boxed Nullable<T>
493                                                         memberType == Globals.TypeOfValueType ||
494                                                         ((IList)Globals.TypeOfNullable.GetInterfaces()).Contains(memberType)) {
495                                                         var unwrappedMemberValue = CodeInterpreter.ConvertValue (memberValue, memberType.GetType (), Globals.TypeOfObject);
496                                                         memberValue = unwrappedMemberValue;
497                                                         isNull2 = memberValue == null;
498                                                 }
499                                                 if (isNull2) {
500                                                         XmlFormatGeneratorStatics.WriteNullMethod.Invoke (ctx, new object [] {writer, memberType, DataContract.IsTypeSerializable(memberType)});
501                                                 } else {
502                                                         InternalSerialize((isNullableOfT ? XmlFormatGeneratorStatics.InternalSerializeMethod : XmlFormatGeneratorStatics.InternalSerializeReferenceMethod),
503                                                                 () => memberValue, memberType, writeXsiType);
504                                                 }
505                                         }
506                                 }
507                         }
508                 }
509
510                 void InternalSerialize (MethodInfo methodInfo, Func<object> memberValue, Type memberType, bool writeXsiType)
511                 {
512                         var v = memberValue ();
513                         var typeHandleValue = Type.GetTypeHandle (v);
514                         var isDeclaredType = typeHandleValue.Equals (CodeInterpreter.ConvertValue (v, memberType, Globals.TypeOfObject));
515                         methodInfo.Invoke (ctx, new object [] {writer, memberValue != null ? v : null, isDeclaredType, writeXsiType, DataContract.GetId (memberType.TypeHandle), memberType.TypeHandle});
516                 }
517
518                 object UnwrapNullableObject(Func<object> memberValue, ref Type memberType, out bool isNull)// Leaves !HasValue on stack
519                 {
520                         object v = memberValue ();
521                         isNull = false;
522                         while (memberType.IsGenericType && memberType.GetGenericTypeDefinition () == Globals.TypeOfNullable) {
523                                 Type innerType = memberType.GetGenericArguments () [0];
524                                 if ((bool) XmlFormatGeneratorStatics.GetHasValueMethod.MakeGenericMethod (innerType).Invoke (null, new object [] {v}))
525                                         v = XmlFormatGeneratorStatics.GetNullableValueMethod.MakeGenericMethod (innerType).Invoke (null, new object [] {v});
526                                 else {
527                                         isNull = true;
528                                         v = XmlFormatGeneratorStatics.GetDefaultValueMethod.MakeGenericMethod (memberType).Invoke (null, new object [0]);
529                                 }
530                                 memberType = innerType;
531                         }
532                         
533                         return v;
534                 }
535
536                 bool TryWritePrimitive(Type type, Func<object> value, MemberInfo memberInfo, int? arrayItemIndex, XmlDictionaryString ns, XmlDictionaryString name, int nameIndex)
537                 {
538                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);
539                         if (primitiveContract == null || primitiveContract.UnderlyingType == Globals.TypeOfObject)
540                                 return false;
541
542                         object callee = null;
543                         var args = new List<object> ();
544
545                         // load xmlwriter
546                         if (type.IsValueType)
547                                 callee = writer;
548                         else {
549                                 callee = ctx;
550                                 args.Add (writer);
551                         }
552                         // load primitive value 
553                         if (value != null)
554                                 args.Add (value ());
555                         else if (memberInfo != null)
556                                 args.Add (CodeInterpreter.GetMember (memberInfo, objLocal));
557                         else
558                                 args.Add (((Array) objLocal).GetValue (new int [] {(int) arrayItemIndex}));
559                         // load name
560                         if (name != null)
561                                 args.Add (name);
562                         else
563                                 args.Add (memberNames [nameIndex]);
564                         // load namespace
565                         args.Add (ns);
566                         // call method to write primitive
567                         primitiveContract.XmlFormatWriterMethod.Invoke (callee, args.ToArray ());
568                         return true;
569                 }
570
571                 bool TryWritePrimitiveArray (Type type, Type itemType, Func<object> value, XmlDictionaryString itemName, XmlDictionaryString itemNamespace)
572                 {
573                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType);
574                         if (primitiveContract == null)
575                                 return false;
576
577                         string writeArrayMethod = null;
578                         switch (Type.GetTypeCode(itemType))
579                         {
580                         case TypeCode.Boolean:
581                                 writeArrayMethod = "WriteBooleanArray";
582                                 break;
583                         case TypeCode.DateTime:
584                                 writeArrayMethod = "WriteDateTimeArray";
585                                 break;
586                         case TypeCode.Decimal:
587                                 writeArrayMethod = "WriteDecimalArray";
588                                 break;
589                         case TypeCode.Int32:
590                                 writeArrayMethod = "WriteInt32Array";
591                                 break;
592                         case TypeCode.Int64:
593                                 writeArrayMethod = "WriteInt64Array";
594                                 break;
595                         case TypeCode.Single:
596                                 writeArrayMethod = "WriteSingleArray";
597                                 break;
598                         case TypeCode.Double:
599                                 writeArrayMethod = "WriteDoubleArray";
600                                 break;
601                         default:
602                                 break;
603                         }
604                         if (writeArrayMethod != null)
605                         {
606                                 typeof (XmlWriterDelegator).GetMethod (writeArrayMethod, Globals.ScanAllMembers, null, new Type[] { type, typeof (XmlDictionaryString), typeof (XmlDictionaryString) }, null).Invoke (writer, new object [] {value (), itemName, itemNamespace});
607                                 return true;
608                         }
609                         return false;
610                 }
611
612                 object LoadMemberValue (DataMember member)
613                 {
614                         return CodeInterpreter.GetMember (member.MemberInfo, objLocal);
615                 }
616         }
617 }