[S.R.Serialization] additional type check for array serialization is needed.
[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                                 MethodInfo incrementCollectionCountMethod = null;
199                                 switch (collectionContract.Kind)
200                                 {
201                                 case CollectionKind.Collection:
202                                 case CollectionKind.List:
203                                 case CollectionKind.Dictionary:
204                                         incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountMethod;
205                                         break;
206                                 case CollectionKind.GenericCollection:
207                                 case CollectionKind.GenericList:
208                                         incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(collectionContract.ItemType);
209                                         break;
210                                 case CollectionKind.GenericDictionary:
211                                         incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments()));
212                                         break;
213                                 }
214                                 if (incrementCollectionCountMethod != null)
215                                         incrementCollectionCountMethod.Invoke (ctx, new object [] {writer, objLocal});
216
217                                 bool isDictionary = false, isGenericDictionary = false;
218                                 Type enumeratorType = null;
219                                 Type [] keyValueTypes = null;
220                                 if (collectionContract.Kind == CollectionKind.GenericDictionary)
221                                 {
222                                         isGenericDictionary = true;
223                                         keyValueTypes = collectionContract.ItemType.GetGenericArguments ();
224                                         enumeratorType = Globals.TypeOfGenericDictionaryEnumerator.MakeGenericType (keyValueTypes);
225                                 }
226                                 else if (collectionContract.Kind == CollectionKind.Dictionary)
227                                 {
228                                         isDictionary = true;
229                                         keyValueTypes = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
230                                         enumeratorType = Globals.TypeOfDictionaryEnumerator;
231                                 }
232                                 else
233                                 {
234                                         enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType;
235                                 }
236                                 MethodInfo moveNextMethod = enumeratorType.GetMethod (Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
237                                 MethodInfo getCurrentMethod = enumeratorType.GetMethod (Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
238                                 if (moveNextMethod == null || getCurrentMethod == null)
239                                 {
240                                         if (enumeratorType.IsInterface)
241                                         {
242                                                 if (moveNextMethod == null)
243                                                         moveNextMethod = XmlFormatGeneratorStatics.MoveNextMethod;
244                                                 if (getCurrentMethod == null)
245                                                         getCurrentMethod = XmlFormatGeneratorStatics.GetCurrentMethod;
246                                         }
247                                         else
248                                         {
249                                                 Type ienumeratorInterface = Globals.TypeOfIEnumerator;
250                                                 CollectionKind kind = collectionContract.Kind;
251                                                 if (kind == CollectionKind.GenericDictionary || kind == CollectionKind.GenericCollection || kind == CollectionKind.GenericEnumerable)
252                                                 {
253                                                         Type[] interfaceTypes = enumeratorType.GetInterfaces();
254                                                         foreach (Type interfaceType in interfaceTypes)
255                                                         {
256                                                                 if (interfaceType.IsGenericType
257                                                                         && interfaceType.GetGenericTypeDefinition() == Globals.TypeOfIEnumeratorGeneric
258                                                                         && interfaceType.GetGenericArguments()[0] == collectionContract.ItemType)
259                                                                 {
260                                                                         ienumeratorInterface = interfaceType;
261                                                                         break;
262                                                                 }
263                                                         }
264                                                 }
265                                                 if (moveNextMethod == null)
266                                                         moveNextMethod = CollectionDataContract.GetTargetMethodWithName(Globals.MoveNextMethodName, enumeratorType, ienumeratorInterface);
267                                                 if (getCurrentMethod == null)
268                                                         getCurrentMethod = CollectionDataContract.GetTargetMethodWithName(Globals.GetCurrentMethodName, enumeratorType, ienumeratorInterface);
269                                         }
270                                 }
271                                 Type elementType = getCurrentMethod.ReturnType;
272                                 object currentValue = null; // of elementType
273
274                                 var enumerator = (IEnumerator) collectionContract.GetEnumeratorMethod.Invoke (objLocal, new object [0]);
275                                 if (isDictionary)
276                                 {
277                                         enumerator = new CollectionDataContract.DictionaryEnumerator ((IDictionaryEnumerator) enumerator);
278                                 }
279                                 else if (isGenericDictionary)
280                                 {
281                                         Type ctorParam = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes));
282                                         ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { ctorParam }, null);
283                                         enumerator = (IEnumerator) Activator.CreateInstance (enumeratorType, new object [] {enumerator});
284                                 }
285
286                                 var emptyArray = new object [0];
287                                 while (enumerator != null && enumerator.MoveNext ()) {
288                                         currentValue = getCurrentMethod.Invoke (enumerator, emptyArray);
289
290                                         if (incrementCollectionCountMethod == null)
291                                                 XmlFormatGeneratorStatics.IncrementItemCountMethod.Invoke (ctx, new object [] {1});
292
293                                         if (!TryWritePrimitive (elementType, () => currentValue, null, null, itemNamespace, itemName, 0))
294                                         {
295                                                 WriteStartElement (elementType, collectionContract.Namespace, itemNamespace, itemName, 0);
296                                                 if (isGenericDictionary || isDictionary)
297                                                         collectionDataContract.ItemContract.WriteXmlValue (writer, currentValue, ctx);
298                                                 else
299                                                         WriteValue (elementType, currentValue, false);
300                                                 WriteEndElement();
301                                         }
302                                 }
303                         }
304                 }
305
306                 int WriteMembers (ClassDataContract classContract, ExtensionDataObject extensionData, ClassDataContract derivedMostClassContract)
307                 {
308                         int memberCount = (classContract.BaseContract == null) ? 0 : WriteMembers (classContract.BaseContract, extensionData, derivedMostClassContract);
309
310                         XmlDictionaryString ns = 
311                                 (contractNamespaces == null) ? dataContract.Namespace :
312                                 contractNamespaces [typeIndex - 1];
313
314                         ctx.IncrementItemCount (classContract.Members.Count);
315
316                         for (int i = 0; i < classContract.Members.Count; i++, memberCount++) {
317
318                                 DataMember member = classContract.Members[i];
319                                 Type memberType = member.MemberType;
320                                 object memberValue = null;
321                                 if (member.IsGetOnlyCollection)
322                                         ctx.StoreIsGetOnlyCollection ();
323                                 bool doWrite = true, hasMemberValue = false;
324                                 if (!member.EmitDefaultValue)
325                                 {
326                                         hasMemberValue = true;
327                                         memberValue = LoadMemberValue (member);
328                                         doWrite = !IsDefaultValue (memberType, memberValue);
329                                 }
330
331                                 if (doWrite) {
332
333                                         bool writeXsiType = CheckIfMemberHasConflict (member, classContract, derivedMostClassContract);
334                                         if (writeXsiType || !TryWritePrimitive (memberType, hasMemberValue ? () => memberValue : (Func<object>) null, member.MemberInfo, null /*arrayItemIndex*/, ns, null /*nameLocal*/, i + childElementIndex)) {
335                                                 WriteStartElement (memberType, classContract.Namespace, ns, null /*nameLocal*/, i + childElementIndex);
336                                                 if (classContract.ChildElementNamespaces [i + childElementIndex] != null)
337                                                         writer.WriteNamespaceDecl (childElementNamespaces [i + childElementIndex]);
338                                                 if (memberValue == null)
339                                                         memberValue = LoadMemberValue (member);
340                                                 WriteValue (memberType, memberValue, writeXsiType);
341                                                 WriteEndElement ();
342                                         }
343
344                                         if (classContract.HasExtensionData)
345                                                 ctx.WriteExtensionData (writer, extensionData, memberCount);
346                                 } else if (!member.EmitDefaultValue) {
347                                         if (member.IsRequired)
348                                                 XmlObjectSerializerWriteContext.ThrowRequiredMemberMustBeEmitted (member.Name, classContract.UnderlyingType);
349                                 }
350                         }
351
352                         typeIndex++;
353                         childElementIndex += classContract.Members.Count;
354                         return memberCount;
355                 }
356
357
358                 internal bool IsDefaultValue (Type type, object value)
359                 {
360                         return GetDefaultValue (type).Equals (value);
361                 }
362
363                 internal object GetDefaultValue(Type type)
364                 {
365                         if (type.IsValueType)
366                         {
367                                 switch (Type.GetTypeCode(type))
368                                 {
369                                 case TypeCode.Boolean:
370                                         return false;
371                                 case TypeCode.Char:
372                                 case TypeCode.SByte:
373                                 case TypeCode.Byte:
374                                 case TypeCode.Int16:
375                                 case TypeCode.UInt16:
376                                 case TypeCode.Int32:
377                                 case TypeCode.UInt32:
378                                         return 0;
379                                 case TypeCode.Int64:
380                                 case TypeCode.UInt64:
381                                         return 0L;
382                                 case TypeCode.Single:
383                                         return 0.0F;
384                                 case TypeCode.Double:
385                                         return 0.0;
386                                 case TypeCode.Decimal:
387                                         return default (decimal);
388                                 case TypeCode.DateTime:
389                                         return default (DateTime);
390                                 }
391                         }
392                         return null;
393                 }
394
395                 bool CheckIfMemberHasConflict(DataMember member, ClassDataContract classContract, ClassDataContract derivedMostClassContract)
396                 {
397                         // Check for conflict with base type members
398                         if (CheckIfConflictingMembersHaveDifferentTypes(member))
399                                 return true;
400
401                         // Check for conflict with derived type members
402                         string name = member.Name;
403                         string ns = classContract.StableName.Namespace;
404                         ClassDataContract currentContract = derivedMostClassContract;
405                         while (currentContract != null && currentContract != classContract)
406                         {
407                                 if (ns == currentContract.StableName.Namespace)
408                                 {
409                                         List<DataMember> members = currentContract.Members;
410                                         for (int j = 0; j < members.Count; j++)
411                                         {
412                                                 if (name == members[j].Name)
413                                                         return CheckIfConflictingMembersHaveDifferentTypes(members[j]);
414                                         }
415                                 }
416                                 currentContract = currentContract.BaseContract;
417                         }
418
419                         return false;
420                 }
421
422                 bool CheckIfConflictingMembersHaveDifferentTypes(DataMember member)
423                 {
424                         while (member.ConflictingMember != null)
425                         {
426                                 if (member.MemberType != member.ConflictingMember.MemberType)
427                                         return true;
428                                 member = member.ConflictingMember;
429                         }
430                         return false;
431                 }
432
433                 bool NeedsPrefix(Type type, XmlDictionaryString ns)
434                 {
435                         return type == Globals.TypeOfXmlQualifiedName && (ns != null && ns.Value != null && ns.Value.Length > 0);
436                 }
437
438                 void WriteStartElement (Type type, XmlDictionaryString ns, XmlDictionaryString namespaceLocal, XmlDictionaryString nameLocal, int nameIndex)
439                 {
440                         bool needsPrefix = NeedsPrefix(type, ns);
441                         nameLocal = nameLocal ?? memberNames [nameIndex];
442                         if (needsPrefix)
443                                 writer.WriteStartElement (Globals.ElementPrefix, nameLocal, namespaceLocal);
444                         else
445                                 writer.WriteStartElement (nameLocal, namespaceLocal);
446                 }
447
448                 void WriteEndElement ()
449                 {
450                         writer.WriteEndElement ();
451                 }
452
453                 void WriteValue (Type memberType, object memberValue, bool writeXsiType)
454                 {
455                         Pointer memberValueRefPointer = null;
456                         if (memberType.IsPointer)
457                                 memberValueRefPointer = (Pointer) XmlFormatGeneratorStatics.BoxPointer.Invoke (null, new object [] {memberValue, memberType});
458                         bool isNullableOfT = (memberType.IsGenericType &&
459                                 memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable);
460                         if (memberType.IsValueType && !isNullableOfT)
461                         {
462                                 PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
463                                 if (primitiveContract != null && !writeXsiType)
464                                         primitiveContract.XmlFormatContentWriterMethod.Invoke (writer, new object [] {memberValue});
465                                 else
466                                         InternalSerialize(XmlFormatGeneratorStatics.InternalSerializeMethod, () => memberValue, memberType, writeXsiType);
467                         }
468                         else
469                         {
470                                 bool isNull;
471                                 if (isNullableOfT)
472                                         memberValue = UnwrapNullableObject(() => memberValue, ref memberType, out isNull); //Leaves !HasValue on stack
473                                 else
474                                         isNull = memberValue == null;
475                                 if (isNull)
476                                         XmlFormatGeneratorStatics.WriteNullMethod.Invoke (ctx, new object [] {writer, memberType, DataContract.IsTypeSerializable(memberType)});
477                                 else {
478                                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
479                                         if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject && !writeXsiType) {
480                                                 if (isNullableOfT)
481                                                         primitiveContract.XmlFormatContentWriterMethod.Invoke (writer, new object [] {memberValue});
482                                                 else                                                    
483                                                         primitiveContract.XmlFormatContentWriterMethod.Invoke (ctx, new object [] {writer, memberValue});
484                                         } else {
485                                                 bool isNull2 = false;
486                                                 if (memberType == Globals.TypeOfObject || //boxed Nullable<T>
487                                                         memberType == Globals.TypeOfValueType ||
488                                                         ((IList)Globals.TypeOfNullable.GetInterfaces()).Contains(memberType)) {
489                                                         var unwrappedMemberValue = CodeInterpreter.ConvertValue (memberValue, memberType.GetType (), Globals.TypeOfObject);
490                                                         memberValue = unwrappedMemberValue;
491                                                         isNull2 = memberValue == null;
492                                                 }
493                                                 if (isNull2) {
494                                                         XmlFormatGeneratorStatics.WriteNullMethod.Invoke (ctx, new object [] {writer, memberType, DataContract.IsTypeSerializable(memberType)});
495                                                 } else {
496                                                         InternalSerialize((isNullableOfT ? XmlFormatGeneratorStatics.InternalSerializeMethod : XmlFormatGeneratorStatics.InternalSerializeReferenceMethod),
497                                                                 () => memberValue, memberType, writeXsiType);
498                                                 }
499                                         }
500                                 }
501                         }
502                 }
503
504                 void InternalSerialize (MethodInfo methodInfo, Func<object> memberValue, Type memberType, bool writeXsiType)
505                 {
506                         var v = memberValue ();
507                         var typeHandleValue = Type.GetTypeHandle (v);
508                         var isDeclaredType = typeHandleValue.Equals (CodeInterpreter.ConvertValue (v, memberType, Globals.TypeOfObject));
509                         methodInfo.Invoke (ctx, new object [] {writer, memberValue != null ? v : null, isDeclaredType, writeXsiType, DataContract.GetId (memberType.TypeHandle), memberType.TypeHandle});
510                 }
511
512                 object UnwrapNullableObject(Func<object> memberValue, ref Type memberType, out bool isNull)// Leaves !HasValue on stack
513                 {
514                         object v = memberValue ();
515                         isNull = false;
516                         while (memberType.IsGenericType && memberType.GetGenericTypeDefinition () == Globals.TypeOfNullable) {
517                                 Type innerType = memberType.GetGenericArguments () [0];
518                                 if ((bool) XmlFormatGeneratorStatics.GetHasValueMethod.MakeGenericMethod (innerType).Invoke (null, new object [] {v}))
519                                         v = XmlFormatGeneratorStatics.GetNullableValueMethod.MakeGenericMethod (innerType).Invoke (null, new object [] {v});
520                                 else {
521                                         isNull = true;
522                                         v = XmlFormatGeneratorStatics.GetDefaultValueMethod.MakeGenericMethod (memberType).Invoke (null, new object [0]);
523                                 }
524                                 memberType = innerType;
525                         }
526                         
527                         return v;
528                 }
529
530                 bool TryWritePrimitive(Type type, Func<object> value, MemberInfo memberInfo, int? arrayItemIndex, XmlDictionaryString ns, XmlDictionaryString name, int nameIndex)
531                 {
532                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);
533                         if (primitiveContract == null || primitiveContract.UnderlyingType == Globals.TypeOfObject)
534                                 return false;
535
536                         object callee = null;
537                         var args = new List<object> ();
538
539                         // load xmlwriter
540                         if (type.IsValueType)
541                                 callee = writer;
542                         else {
543                                 callee = ctx;
544                                 args.Add (writer);
545                         }
546                         // load primitive value 
547                         if (value != null)
548                                 args.Add (value ());
549                         else if (memberInfo != null)
550                                 args.Add (CodeInterpreter.GetMember (memberInfo, objLocal));
551                         else
552                                 args.Add (((Array) objLocal).GetValue (new int [] {(int) arrayItemIndex}));
553                         // load name
554                         if (name != null)
555                                 args.Add (name);
556                         else {
557                                 if (memberNames.Length <= nameIndex) throw new Exception (string.Format ("@@@@@@@@@@@@@@@@@@@ {0} {1} ({2}/{3})", type, memberInfo, nameIndex, memberNames.Length));
558                                 args.Add (memberNames [nameIndex]);
559                         }
560                         // load namespace
561                         args.Add (ns);
562                         // call method to write primitive
563                         primitiveContract.XmlFormatWriterMethod.Invoke (callee, args.ToArray ());
564                         return true;
565                 }
566
567                 bool TryWritePrimitiveArray (Type type, Type itemType, Func<object> value, XmlDictionaryString itemName, XmlDictionaryString itemNamespace)
568                 {
569                         PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType);
570                         if (primitiveContract == null)
571                                 return false;
572
573                         string writeArrayMethod = null;
574                         switch (Type.GetTypeCode(itemType))
575                         {
576                         case TypeCode.Boolean:
577                                 writeArrayMethod = "WriteBooleanArray";
578                                 break;
579                         case TypeCode.DateTime:
580                                 writeArrayMethod = "WriteDateTimeArray";
581                                 break;
582                         case TypeCode.Decimal:
583                                 writeArrayMethod = "WriteDecimalArray";
584                                 break;
585                         case TypeCode.Int32:
586                                 writeArrayMethod = "WriteInt32Array";
587                                 break;
588                         case TypeCode.Int64:
589                                 writeArrayMethod = "WriteInt64Array";
590                                 break;
591                         case TypeCode.Single:
592                                 writeArrayMethod = "WriteSingleArray";
593                                 break;
594                         case TypeCode.Double:
595                                 writeArrayMethod = "WriteDoubleArray";
596                                 break;
597                         default:
598                                 break;
599                         }
600                         if (writeArrayMethod != null)
601                         {
602                                 typeof (XmlWriterDelegator).GetMethod (writeArrayMethod, Globals.ScanAllMembers, null, new Type[] { type, typeof (XmlDictionaryString), typeof (XmlDictionaryString) }, null).Invoke (writer, new object [] {value (), itemName, itemNamespace});
603                                 return true;
604                         }
605                         return false;
606                 }
607
608                 object LoadMemberValue (DataMember member)
609                 {
610                         return CodeInterpreter.GetMember (member.MemberInfo, objLocal);
611                 }
612         }
613 }