[S.R.Serialization] implemented interpreter-based XmlFormatWriterGenerator.
authorAtsushi Eno <atsushieno@gmail.com>
Thu, 2 Apr 2015 19:43:57 +0000 (04:43 +0900)
committerAtsushi Eno <atsushieno@gmail.com>
Fri, 24 Apr 2015 05:36:51 +0000 (14:36 +0900)
mcs/class/System.Runtime.Serialization/ReferenceSources/CodeInterpreter.cs [new file with mode: 0644]
mcs/class/System.Runtime.Serialization/ReferenceSources/XmlFormatWriterGenerator_static.cs
mcs/class/System.Runtime.Serialization/System.Runtime.Serialization.dll.sources

diff --git a/mcs/class/System.Runtime.Serialization/ReferenceSources/CodeInterpreter.cs b/mcs/class/System.Runtime.Serialization/ReferenceSources/CodeInterpreter.cs
new file mode 100644 (file)
index 0000000..9be92ef
--- /dev/null
@@ -0,0 +1,64 @@
+
+namespace System.Runtime.Serialization
+{
+       public class CodeInterpreter
+       {
+
+               internal static object ConvertValue(object arg, Type source, Type target)
+               {
+                       return InternalConvert(arg, source, target, false);
+               }
+
+
+        static bool CanConvert (TypeCode typeCode)
+        {
+            switch (typeCode)
+            {
+                case TypeCode.Boolean:
+                case TypeCode.Char:
+                case TypeCode.SByte:
+                case TypeCode.Byte:
+                case TypeCode.Int16:
+                case TypeCode.UInt16:
+                case TypeCode.Int32:
+                case TypeCode.UInt32:
+                case TypeCode.Int64:
+                case TypeCode.UInt64:
+                case TypeCode.Single:
+                case TypeCode.Double:
+                                       return true;
+            }
+            return false;
+        }
+
+               static object InternalConvert(object arg, Type source, Type target, bool isAddress)
+               {
+
+            if (target == source)
+                return arg;
+            if (target.IsValueType)
+            {
+                if (source.IsValueType)
+                {
+                    if (CanConvert (Type.GetTypeCode(target)))
+                        throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.NoConversionPossibleTo, DataContract.GetClrTypeFullName(target))));
+                    else
+                                               return target;
+                }
+                else if (source.IsAssignableFrom(target))
+                                       return arg;
+                else
+                    throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.IsNotAssignableFrom, DataContract.GetClrTypeFullName(target), DataContract.GetClrTypeFullName(source))));
+            }
+            else if (target.IsAssignableFrom(source))
+                               return arg;
+            else if (source.IsAssignableFrom(target))
+                               return arg;
+            else if (target.IsInterface || source.IsInterface)
+                               return arg;
+            else
+                throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.IsNotAssignableFrom, DataContract.GetClrTypeFullName(target), DataContract.GetClrTypeFullName(source))));
+               }
+       }
+}
+
index 71d2af81c73a3e27a2a57d32fc5c4be46b332f13..571ac1e34694d6371c09a28af81996edd2a05e1b 100644 (file)
@@ -1,4 +1,5 @@
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
@@ -12,13 +13,608 @@ namespace System.Runtime.Serialization
                {
                        internal XmlFormatClassWriterDelegate GenerateClassWriter(ClassDataContract classContract)
                        {
-                               throw new NotImplementedException ();
+                               return (XmlWriterDelegator xw, object obj, XmlObjectSerializerWriteContext ctx, ClassDataContract ctr) => new XmlFormatWriterInterpreter (classContract).WriteToXml (xw, obj, ctx, ctr);
                        }
+
                        internal XmlFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionDataContract collectionContract)
                        {
-                               throw new NotImplementedException ();
+                               return (XmlWriterDelegator xw, object obj, XmlObjectSerializerWriteContext ctx, CollectionDataContract ctr) => new XmlFormatWriterInterpreter (collectionContract).WriteCollectionToXml (xw, obj, ctx, ctr);
                        }
                }
        }
-}
 
+       class XmlFormatWriterInterpreter
+       {
+               public XmlFormatWriterInterpreter (ClassDataContract classContract)
+               {
+                       this.classContract = classContract;
+               }
+
+               public XmlFormatWriterInterpreter (CollectionDataContract collectionContract)
+               {
+                       this.collectionContract = collectionContract;
+               }
+
+               ClassDataContract classContract;
+
+               CollectionDataContract collectionContract;
+
+               XmlWriterDelegator writer = null;
+               object obj = null;
+               XmlObjectSerializerWriteContext ctx = null;
+               DataContract dataContract = null;
+               object objLocal = null;
+
+               ClassDataContract classDataContract {
+                       get { return (ClassDataContract) dataContract; }
+               }
+               CollectionDataContract collectionDataContract {
+                       get {return (CollectionDataContract) dataContract; }
+               }
+
+               XmlDictionaryString [] contractNamespaces = null;
+               XmlDictionaryString [] memberNames = null;
+               XmlDictionaryString [] childElementNamespaces = null;
+               int typeIndex = 1;
+               int childElementIndex = 0;
+
+               Dictionary<string,object> memberValues = new Dictionary<string,object> ();
+
+               public void WriteToXml (XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, ClassDataContract dataContract)
+               {
+                       this.writer = xmlWriter;
+                       this.obj = obj;
+                       this.ctx = context;
+                       this.dataContract = dataContract;
+
+                       InitArgs (classContract.UnderlyingType);
+
+                       // DemandSerializationFormatterPermission (classContract) - irrelevant
+                       // DemandMemberAccessPermission (memberAccessFlag) - irrelevant
+
+                       if (classContract.IsReadOnlyContract)
+                       {
+                               DataContract.ThrowInvalidDataContractException (classContract.SerializationExceptionMessage, null);
+                       }
+
+                       WriteClass (classContract);
+               }
+
+               public void WriteCollectionToXml (XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, CollectionDataContract collectionContract)
+               {
+                       this.writer = xmlWriter;
+                       this.obj = obj;
+                       this.ctx = context;
+                       this.dataContract = collectionContract;
+
+                       InitArgs (collectionContract.UnderlyingType);                   
+
+                       // DemandMemberAccessPermission(memberAccessFlag);
+                       if (collectionContract.IsReadOnlyContract)
+                       {
+                               DataContract.ThrowInvalidDataContractException (collectionContract.SerializationExceptionMessage, null);
+                       }
+
+                       WriteCollection (collectionContract);
+               }
+
+               void InitArgs (Type objType)
+               {
+                       if (objType == Globals.TypeOfDateTimeOffsetAdapter) {
+                               objLocal = DateTimeOffsetAdapter.GetDateTimeOffsetAdapter ((DateTimeOffset) obj);
+                       }
+                       else
+                               objLocal = CodeInterpreter.ConvertValue (obj, typeof (object), objType);
+               }
+
+               void InvokeOnSerializing (ClassDataContract classContract, object objSerialized, XmlObjectSerializerWriteContext ctx)
+               {
+                       if (classContract.BaseContract != null)
+                               InvokeOnSerializing (classContract.BaseContract, objSerialized, ctx);
+                       if (classContract.OnSerializing != null) {
+                               classContract.OnSerializing.Invoke (objSerialized, new object [] {ctx.GetStreamingContext ()});
+                       }
+               }
+
+               void InvokeOnSerialized (ClassDataContract classContract, object objSerialized, XmlObjectSerializerWriteContext ctx)
+               {
+                       if (classContract.BaseContract != null)
+                               InvokeOnSerialized (classContract.BaseContract, objSerialized, ctx);
+                       if (classContract.OnSerialized != null) {
+                               classContract.OnSerialized.Invoke (objSerialized, new object [] {ctx.GetStreamingContext ()});
+                       }
+               }
+
+               void WriteClass (ClassDataContract classContract)
+               {
+                       InvokeOnSerializing (classContract, objLocal, ctx);
+
+                       if (classContract.IsISerializable)
+                               ctx.WriteISerializable (writer, (ISerializable) objLocal);
+                       else
+                       {
+                               if (classContract.ContractNamespaces.Length > 1)
+                                       contractNamespaces = classDataContract.ContractNamespaces;
+                               memberNames = classDataContract.MemberNames;
+
+                               for (int i = 0; i < classContract.ChildElementNamespaces.Length; i++)
+                               {
+                                       if (classContract.ChildElementNamespaces[i] != null)
+                                       {
+                                               childElementNamespaces = classDataContract.ChildElementNamespaces;
+                                       }
+                               }
+
+                               if (classContract.HasExtensionData)
+                               {
+                                       ExtensionDataObject extensionData = ((IExtensibleDataObject) objLocal).ExtensionData;
+                                       ctx.WriteExtensionData (writer, extensionData, -1);
+
+                                       WriteMembers (classContract, extensionData, classContract);
+                               }
+                               else
+                                       WriteMembers (classContract, null, classContract);
+                       }
+                       InvokeOnSerialized (classContract, objLocal, ctx);
+               }
+
+               void WriteCollection(CollectionDataContract collectionContract)
+               {
+                       XmlDictionaryString itemNamespace = dataContract.Namespace;
+
+                       XmlDictionaryString itemName = collectionDataContract.CollectionItemName;
+
+                       if (collectionContract.ChildElementNamespace != null)
+                               writer.WriteNamespaceDecl (collectionDataContract.ChildElementNamespace);
+
+                       if (collectionContract.Kind == CollectionKind.Array)
+                       {
+                               Type itemType = collectionContract.ItemType;
+                               int i;
+                               ctx.IncrementArrayCount (writer, (Array) objLocal);
+
+                               if (!TryWritePrimitiveArray(collectionContract.UnderlyingType, itemType, () => objLocal, itemName, itemNamespace))
+                               {
+                                       var arr = (Array) objLocal;
+                                       var idx = new int [1];
+                                       for (i = 0; i < arr.Length; i++) {
+                                               if (!TryWritePrimitive(itemType, null, null, i, itemNamespace, itemName, 0)) {
+                                                       WriteStartElement (itemType, collectionContract.Namespace, itemNamespace, itemName, 0);
+                                                       idx [0] = i;
+                                                       var mbrVal = arr.GetValue (idx);
+                                                       WriteValue (itemType, mbrVal, false);
+                                                       WriteEndElement ();
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               MethodInfo incrementCollectionCountMethod = null;
+                               switch (collectionContract.Kind)
+                               {
+                               case CollectionKind.Collection:
+                               case CollectionKind.List:
+                               case CollectionKind.Dictionary:
+                                       incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountMethod;
+                                       break;
+                               case CollectionKind.GenericCollection:
+                               case CollectionKind.GenericList:
+                                       incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(collectionContract.ItemType);
+                                       break;
+                               case CollectionKind.GenericDictionary:
+                                       incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments()));
+                                       break;
+                               }
+                               if (incrementCollectionCountMethod != null)
+                                       incrementCollectionCountMethod.Invoke (ctx, new object [] {writer, objLocal});
+
+                               bool isDictionary = false, isGenericDictionary = false;
+                               Type enumeratorType = null;
+                               Type [] keyValueTypes = null;
+                               if (collectionContract.Kind == CollectionKind.GenericDictionary)
+                               {
+                                       isGenericDictionary = true;
+                                       keyValueTypes = collectionContract.ItemType.GetGenericArguments ();
+                                       enumeratorType = Globals.TypeOfGenericDictionaryEnumerator.MakeGenericType (keyValueTypes);
+                               }
+                               else if (collectionContract.Kind == CollectionKind.Dictionary)
+                               {
+                                       isDictionary = true;
+                                       keyValueTypes = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
+                                       enumeratorType = Globals.TypeOfDictionaryEnumerator;
+                               }
+                               else
+                               {
+                                       enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType;
+                               }
+                               MethodInfo moveNextMethod = enumeratorType.GetMethod (Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
+                               MethodInfo getCurrentMethod = enumeratorType.GetMethod (Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
+                               if (moveNextMethod == null || getCurrentMethod == null)
+                               {
+                                       if (enumeratorType.IsInterface)
+                                       {
+                                               if (moveNextMethod == null)
+                                                       moveNextMethod = XmlFormatGeneratorStatics.MoveNextMethod;
+                                               if (getCurrentMethod == null)
+                                                       getCurrentMethod = XmlFormatGeneratorStatics.GetCurrentMethod;
+                                       }
+                                       else
+                                       {
+                                               Type ienumeratorInterface = Globals.TypeOfIEnumerator;
+                                               CollectionKind kind = collectionContract.Kind;
+                                               if (kind == CollectionKind.GenericDictionary || kind == CollectionKind.GenericCollection || kind == CollectionKind.GenericEnumerable)
+                                               {
+                                                       Type[] interfaceTypes = enumeratorType.GetInterfaces();
+                                                       foreach (Type interfaceType in interfaceTypes)
+                                                       {
+                                                               if (interfaceType.IsGenericType
+                                                                       && interfaceType.GetGenericTypeDefinition() == Globals.TypeOfIEnumeratorGeneric
+                                                                       && interfaceType.GetGenericArguments()[0] == collectionContract.ItemType)
+                                                               {
+                                                                       ienumeratorInterface = interfaceType;
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                               if (moveNextMethod == null)
+                                                       moveNextMethod = CollectionDataContract.GetTargetMethodWithName(Globals.MoveNextMethodName, enumeratorType, ienumeratorInterface);
+                                               if (getCurrentMethod == null)
+                                                       getCurrentMethod = CollectionDataContract.GetTargetMethodWithName(Globals.GetCurrentMethodName, enumeratorType, ienumeratorInterface);
+                                       }
+                               }
+                               Type elementType = getCurrentMethod.ReturnType;
+                               object currentValue = null; // of elementType
+
+                               IEnumerator enumerator = null; // of enumeratorType
+                               var e = collectionContract.GetEnumeratorMethod.Invoke (objLocal, new object [0]);
+                               if (isDictionary)
+                               {
+                                       enumerator = new CollectionDataContract.DictionaryEnumerator ((IDictionaryEnumerator) e);
+                               }
+                               else if (isGenericDictionary)
+                               {
+                                       Type ctorParam = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes));
+                                       ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { ctorParam }, null);
+                                       enumerator = (IEnumerator) Activator.CreateInstance (enumeratorType, new object [] {e});
+                               }
+
+                               var emptyArray = new object [0];
+                               while (enumerator != null && enumerator.MoveNext ()) {
+                                       currentValue = getCurrentMethod.Invoke (enumerator, emptyArray);
+
+                                       if (incrementCollectionCountMethod == null)
+                                               XmlFormatGeneratorStatics.IncrementItemCountMethod.Invoke (ctx, new object [] {1});
+
+                                       if (!TryWritePrimitive (elementType, () => currentValue, null, null, itemNamespace, itemName, 0))
+                                       {
+                                               WriteStartElement (elementType, collectionContract.Namespace, itemNamespace, itemName, 0);
+                                               if (isGenericDictionary || isDictionary)
+                                                       collectionDataContract.ItemContract.WriteXmlValue (writer, currentValue, ctx);
+                                               else
+                                                       WriteValue (currentValue.GetType (), currentValue, false);
+                                               WriteEndElement();
+                                       }
+                               }
+                       }
+               }
+
+               int WriteMembers (ClassDataContract classContract, ExtensionDataObject extensionData, ClassDataContract derivedMostClassContract)
+               {
+                       int memberCount = (classContract.BaseContract == null) ? 0 : WriteMembers (classContract.BaseContract, extensionData, derivedMostClassContract);
+
+                       XmlDictionaryString ns = 
+                               (contractNamespaces == null) ? dataContract.Namespace :
+                               contractNamespaces [typeIndex - 1];
+
+                       ctx.IncrementItemCount (classContract.Members.Count);
+
+                       for (int i = 0; i < classContract.Members.Count; i++, memberCount++) {
+
+                               DataMember member = classContract.Members[i];
+                               Type memberType = member.MemberType;
+                               object memberValue = null;
+                               if (member.IsGetOnlyCollection)
+                                       ctx.StoreIsGetOnlyCollection ();
+                               bool doWrite = true;
+                               if (!member.EmitDefaultValue)
+                               {
+                                       memberValue = LoadMemberValue (member);
+                                       doWrite = IsDefaultValue (memberType, memberValue);
+                               }
+
+                               if (doWrite) {
+
+                                       bool writeXsiType = CheckIfMemberHasConflict (member, classContract, derivedMostClassContract);
+                                       if (writeXsiType || !TryWritePrimitive (memberType, () =>memberValue, member.MemberInfo, null /*arrayItemIndex*/, ns, null /*nameLocal*/, i + childElementIndex)) {
+                                               WriteStartElement (memberType, classContract.Namespace, ns, null /*nameLocal*/, i + childElementIndex);
+                                               if (classContract.ChildElementNamespaces [i + childElementIndex] != null)
+                                                       writer.WriteNamespaceDecl (childElementNamespaces [i + childElementIndex]);
+                                               if (memberValue == null)
+                                                       memberValue = LoadMemberValue (member);
+                                               WriteValue (memberType, memberValue, writeXsiType);
+                                               WriteEndElement ();
+                                       }
+
+                                       if (classContract.HasExtensionData)
+                                               ctx.WriteExtensionData (writer, extensionData, memberCount);
+                               } else if (!member.EmitDefaultValue) {
+                                       if (member.IsRequired)
+                                               XmlObjectSerializerWriteContext.ThrowRequiredMemberMustBeEmitted (member.Name, classContract.UnderlyingType);
+                               }
+                       }
+
+                       typeIndex++;
+                       childElementIndex += classContract.Members.Count;
+                       return memberCount;
+               }
+
+
+               internal bool IsDefaultValue (Type type, object value)
+               {
+                       return GetDefaultValue (type).Equals (value);
+               }
+
+               internal object GetDefaultValue(Type type)
+               {
+                       if (type.IsValueType)
+                       {
+                               switch (Type.GetTypeCode(type))
+                               {
+                               case TypeCode.Boolean:
+                                       return false;
+                               case TypeCode.Char:
+                               case TypeCode.SByte:
+                               case TypeCode.Byte:
+                               case TypeCode.Int16:
+                               case TypeCode.UInt16:
+                               case TypeCode.Int32:
+                               case TypeCode.UInt32:
+                                       return 0;
+                               case TypeCode.Int64:
+                               case TypeCode.UInt64:
+                                       return 0L;
+                               case TypeCode.Single:
+                                       return 0.0F;
+                               case TypeCode.Double:
+                                       return 0.0;
+                               case TypeCode.Decimal:
+                                       return default (decimal);
+                               case TypeCode.DateTime:
+                                       return default (DateTime);
+                               }
+                       }
+                       return null;
+               }
+
+               object GetMember (MemberInfo memberInfo, object instance)
+               {
+                       var pi = memberInfo as PropertyInfo;
+                       if (pi != null)
+                               return pi.GetValue (instance);
+                       else
+                               return ((FieldInfo) memberInfo).GetValue (instance);
+               }
+
+               bool CheckIfMemberHasConflict(DataMember member, ClassDataContract classContract, ClassDataContract derivedMostClassContract)
+               {
+                       // Check for conflict with base type members
+                       if (CheckIfConflictingMembersHaveDifferentTypes(member))
+                               return true;
+
+                       // Check for conflict with derived type members
+                       string name = member.Name;
+                       string ns = classContract.StableName.Namespace;
+                       ClassDataContract currentContract = derivedMostClassContract;
+                       while (currentContract != null && currentContract != classContract)
+                       {
+                               if (ns == currentContract.StableName.Namespace)
+                               {
+                                       List<DataMember> members = currentContract.Members;
+                                       for (int j = 0; j < members.Count; j++)
+                                       {
+                                               if (name == members[j].Name)
+                                                       return CheckIfConflictingMembersHaveDifferentTypes(members[j]);
+                                       }
+                               }
+                               currentContract = currentContract.BaseContract;
+                       }
+
+                       return false;
+               }
+
+               bool CheckIfConflictingMembersHaveDifferentTypes(DataMember member)
+               {
+                       while (member.ConflictingMember != null)
+                       {
+                               if (member.MemberType != member.ConflictingMember.MemberType)
+                                       return true;
+                               member = member.ConflictingMember;
+                       }
+                       return false;
+               }
+
+               bool NeedsPrefix(Type type, XmlDictionaryString ns)
+               {
+                       return type == Globals.TypeOfXmlQualifiedName && (ns != null && ns.Value != null && ns.Value.Length > 0);
+               }
+
+               void WriteStartElement (Type type, XmlDictionaryString ns, XmlDictionaryString namespaceLocal, XmlDictionaryString nameLocal, int nameIndex)
+               {
+                       bool needsPrefix = NeedsPrefix(type, ns);
+                       nameLocal = nameLocal ?? memberNames [nameIndex];
+                       if (needsPrefix)
+                               writer.WriteStartElement (Globals.ElementPrefix, nameLocal, namespaceLocal);
+                       else
+                               writer.WriteStartElement (nameLocal, namespaceLocal);
+               }
+
+               void WriteEndElement ()
+               {
+                       writer.WriteEndElement ();
+               }
+
+               void WriteValue (Type memberType, object memberValue, bool writeXsiType)
+               {
+                       Pointer memberValueRefPointer = null;
+                       if (memberType.IsPointer)
+                               memberValueRefPointer = (Pointer) XmlFormatGeneratorStatics.BoxPointer.Invoke (null, new object [] {memberValue, memberType});
+                       bool isNullableOfT = (memberType.IsGenericType &&
+                               memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable);
+                       if (memberType.IsValueType && !isNullableOfT)
+                       {
+                               PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
+                               if (primitiveContract != null && !writeXsiType)
+                                       primitiveContract.XmlFormatContentWriterMethod.Invoke (writer, new object [] {memberValue});
+                               else
+                                       InternalSerialize(XmlFormatGeneratorStatics.InternalSerializeMethod, () => memberValue, memberType, writeXsiType);
+                       }
+                       else
+                       {
+                               bool isNull;
+                               if (isNullableOfT)
+                               {
+                                       memberValue = UnwrapNullableObject(() => memberValue, ref memberType, out isNull); //Leaves !HasValue on stack
+                               }
+                               else
+                                       isNull = memberValue == null;
+                               if (isNull)
+                                       XmlFormatGeneratorStatics.WriteNullMethod.Invoke (ctx, new object [] {writer, memberType, DataContract.IsTypeSerializable(memberType)});
+                               else {
+                                       PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
+                                       if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject && !writeXsiType) {
+                                               if (isNullableOfT)
+                                                       primitiveContract.XmlFormatContentWriterMethod.Invoke (writer, new object [] {memberValue});
+                                               else                                                    
+                                                       primitiveContract.XmlFormatContentWriterMethod.Invoke (ctx, new object [] {writer, memberValue});
+                                       } else {
+                                               bool isNull2 = false;
+                                               if (memberType == Globals.TypeOfObject || //boxed Nullable<T>
+                                                       memberType == Globals.TypeOfValueType ||
+                                                       ((IList)Globals.TypeOfNullable.GetInterfaces()).Contains(memberType)) {
+                                                       var unwrappedMemberValue = CodeInterpreter.ConvertValue (memberValue, memberType.GetType (), Globals.TypeOfObject);
+                                                       memberValue = unwrappedMemberValue;
+                                                       memberType = memberValue.GetType ();
+                                                       isNull2 = memberValue == null;
+                                               }
+                                               if (isNull2) {
+                                                       XmlFormatGeneratorStatics.WriteNullMethod.Invoke (ctx, new object [] {writer, memberType, DataContract.IsTypeSerializable(memberType)});
+                                               } else {
+                                                       InternalSerialize((isNullableOfT ? XmlFormatGeneratorStatics.InternalSerializeMethod : XmlFormatGeneratorStatics.InternalSerializeReferenceMethod),
+                                                               () => memberValue, memberType, writeXsiType);
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               void InternalSerialize (MethodInfo methodInfo, Func<object> memberValue, Type memberType, bool writeXsiType)
+               {
+                       var typeHandleValue = Type.GetTypeHandle (memberValue);
+                       var isDeclaredType = typeHandleValue.Equals (CodeInterpreter.ConvertValue (memberValue, memberType, Globals.TypeOfObject));
+                       methodInfo.Invoke (ctx, new object [] {writer, memberValue != null ? memberValue () : null, isDeclaredType, writeXsiType, DataContract.GetId (memberType.TypeHandle), memberType.TypeHandle});
+               }
+
+               object UnwrapNullableObject(Func<object> memberValue, ref Type memberType, out bool isNull)// Leaves !HasValue on stack
+               {
+                       object nullableUnwrappedMemberValue = null;
+                       isNull = false;
+                       while (memberType.IsGenericType && memberType.GetGenericTypeDefinition () == Globals.TypeOfNullable) {
+                               Type innerType = memberType.GetGenericArguments () [0];
+                               if ((bool) XmlFormatGeneratorStatics.GetHasValueMethod.MakeGenericMethod (innerType).Invoke (innerType, new object [0]) == null) {
+                                       isNull = true;
+                                       return XmlFormatGeneratorStatics.GetDefaultValueMethod.MakeGenericMethod (memberType).Invoke (null, new object [0]);
+                               }
+                               nullableUnwrappedMemberValue = XmlFormatGeneratorStatics.GetNullableValueMethod.MakeGenericMethod (innerType).Invoke (memberValue (), new object [0]);
+                               memberType = innerType;
+                       }
+                                               
+                       return memberValue;
+               }
+
+               bool TryWritePrimitive(Type type, Func<object> value, MemberInfo memberInfo, int? arrayItemIndex, XmlDictionaryString ns, XmlDictionaryString name, int nameIndex)
+               {
+                       PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);
+                       if (primitiveContract == null || primitiveContract.UnderlyingType == Globals.TypeOfObject)
+                               return false;
+
+                       object callee = null;
+                       var args = new List<object> ();
+
+                       // load xmlwriter
+                       if (type.IsValueType)
+                               callee = writer;
+                       else {
+                               callee = ctx;
+                               args.Add (writer);
+                       }
+                       // load primitive value 
+                       if (value != null)
+                               args.Add (value ());
+                       else if (memberInfo != null)
+                               args.Add (GetMember (memberInfo, objLocal));
+                       else
+                               args.Add (((Array) objLocal).GetValue (new int [] {(int) arrayItemIndex}));
+                       // load name
+                       if (name != null)
+                               args.Add (name);
+                       else {
+                               if (memberNames.Length <= nameIndex) throw new Exception (string.Format ("@@@@@@@@@@@@@@@@@@@ {0} {1} ({2}/{3})", type, memberInfo, nameIndex, memberNames.Length));
+                               args.Add (memberNames [nameIndex]);
+                       }
+                       // load namespace
+                       args.Add (ns);
+                       // call method to write primitive
+                       primitiveContract.XmlFormatWriterMethod.Invoke (callee, args.ToArray ());
+                       return true;
+               }
+
+               bool TryWritePrimitiveArray (Type type, Type itemType, Func<object> value, XmlDictionaryString itemName, XmlDictionaryString itemNamespace)
+               {
+                       PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType);
+                       if (primitiveContract == null)
+                               return false;
+
+                       string writeArrayMethod = null;
+                       switch (Type.GetTypeCode(itemType))
+                       {
+                       case TypeCode.Boolean:
+                               writeArrayMethod = "WriteBooleanArray";
+                               break;
+                       case TypeCode.DateTime:
+                               writeArrayMethod = "WriteDateTimeArray";
+                               break;
+                       case TypeCode.Decimal:
+                               writeArrayMethod = "WriteDecimalArray";
+                               break;
+                       case TypeCode.Int32:
+                               writeArrayMethod = "WriteInt32Array";
+                               break;
+                       case TypeCode.Int64:
+                               writeArrayMethod = "WriteInt64Array";
+                               break;
+                       case TypeCode.Single:
+                               writeArrayMethod = "WriteSingleArray";
+                               break;
+                       case TypeCode.Double:
+                               writeArrayMethod = "WriteDoubleArray";
+                               break;
+                       default:
+                               break;
+                       }
+                       if (writeArrayMethod != null)
+                       {
+                               typeof (XmlWriterDelegator).GetMethod (writeArrayMethod, Globals.ScanAllMembers, null, new Type[] { type, typeof (XmlDictionaryString), typeof (XmlDictionaryString) }, null).Invoke (writer, new object [] {value (), itemName, itemNamespace});
+                               return true;
+                       }
+                       return false;
+               }
+
+               object LoadMemberValue (DataMember member)
+               {
+                       var v = GetMember (member.MemberInfo, objLocal);
+                       memberValues [member.Name + "Value"] = v;
+                       return v;
+               }
+       }
+}
index d49b1f5adb070a2fd9a72a430246e57af71df004..4eaa3d9fa99c942c97e5173a200345436dbcb747 100644 (file)
@@ -8,6 +8,8 @@ ReferenceSources/FxTrace.cs
 ReferenceSources/SR.cs
 ReferenceSources/SR_missing.cs
 ReferenceSources/XmlExceptionHelper.cs
+
+ReferenceSources/CodeInterpreter.cs
 ReferenceSources/JsonFormatReaderGenerator_static.cs
 ReferenceSources/JsonFormatWriterGenerator_static.cs
 ReferenceSources/XmlDataContract_static.cs