using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Runtime;
+using System.Xml;
namespace System.Runtime.Serialization.Json
{
{
partial class CriticalHelper
{
- public JsonFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
+ internal JsonFormatClassReaderDelegate GenerateClassReader(ClassDataContract classContract)
{
- throw new NotImplementedException ();
+ return (XmlReaderDelegator xr, XmlObjectSerializerReadContextComplexJson ctx, XmlDictionaryString emptyDictionaryString, XmlDictionaryString [] memberNames) => new JsonFormatReaderInterpreter (classContract).ReadFromJson (xr, ctx, emptyDictionaryString, memberNames);
}
- public JsonFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
+
+ internal JsonFormatCollectionReaderDelegate GenerateCollectionReader(CollectionDataContract collectionContract)
{
- throw new NotImplementedException ();
+ return (XmlReaderDelegator xr, XmlObjectSerializerReadContextComplexJson ctx, XmlDictionaryString emptyDS, XmlDictionaryString inm, CollectionDataContract cc) => new JsonFormatReaderInterpreter (collectionContract, false).ReadCollectionFromJson (xr, ctx, emptyDS, inm, cc);
}
- public JsonFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
+
+ internal JsonFormatGetOnlyCollectionReaderDelegate GenerateGetOnlyCollectionReader(CollectionDataContract collectionContract)
{
- throw new NotImplementedException ();
+ return (XmlReaderDelegator xr, XmlObjectSerializerReadContextComplexJson ctx, XmlDictionaryString emptyDS, XmlDictionaryString inm, CollectionDataContract cc) => new JsonFormatReaderInterpreter (collectionContract, true).ReadGetOnlyCollectionFromJson (xr, ctx, emptyDS, inm, cc);
}
}
}
-}
+ class JsonFormatReaderInterpreter
+ {
+ public JsonFormatReaderInterpreter (ClassDataContract classContract)
+ {
+ this.classContract = classContract;
+ }
+
+ public JsonFormatReaderInterpreter (CollectionDataContract collectionContract, bool isGetOnly)
+ {
+ this.collectionContract = collectionContract;
+ this.is_get_only_collection = isGetOnly;
+ }
+
+ bool is_get_only_collection;
+
+ ClassDataContract classContract;
+
+ CollectionDataContract collectionContract;
+
+ object objectLocal;
+ Type objectType;
+ XmlReaderDelegator xmlReader;
+ XmlObjectSerializerReadContextComplexJson context;
+
+ XmlDictionaryString [] memberNames = null;
+ XmlDictionaryString emptyDictionaryString = null;
+ XmlDictionaryString itemName = null;
+ XmlDictionaryString itemNamespace = null;
+
+ public object ReadFromJson (XmlReaderDelegator xmlReader, XmlObjectSerializerReadContextComplexJson context, XmlDictionaryString emptyDictionaryString, XmlDictionaryString[] memberNames)
+ {
+ // InitArgs()
+ this.xmlReader = xmlReader;
+ this.context = context;
+ this.emptyDictionaryString = emptyDictionaryString;
+ this.memberNames = memberNames;
+
+ //DemandSerializationFormatterPermission(classContract);
+ //DemandMemberAccessPermission(memberAccessFlag);
+ CreateObject (classContract);
+
+ context.AddNewObject (objectLocal);
+ InvokeOnDeserializing (classContract);
+
+ string objectId = null;
+
+ if (classContract.IsISerializable)
+ ReadISerializable (classContract);
+ else
+ ReadClass (classContract);
+ if (Globals.TypeOfIDeserializationCallback.IsAssignableFrom (classContract.UnderlyingType))
+ ((IDeserializationCallback) objectLocal).OnDeserialization (null);
+ InvokeOnDeserialized(classContract);
+ if (!InvokeFactoryMethod (classContract)) {
+
+ // Do a conversion back from DateTimeOffsetAdapter to DateTimeOffset after deserialization.
+ // DateTimeOffsetAdapter is used here for deserialization purposes to bypass the ISerializable implementation
+ // on DateTimeOffset; which does not work in partial trust.
+
+ if (classContract.UnderlyingType == Globals.TypeOfDateTimeOffsetAdapter)
+ objectLocal = DateTimeOffsetAdapter.GetDateTimeOffset ((DateTimeOffsetAdapter) objectLocal);
+ // else - do we have to call CodeInterpreter.ConvertValue()? I guess not...
+ }
+ return objectLocal;
+ }
+
+ public object ReadCollectionFromJson (XmlReaderDelegator xmlReader, XmlObjectSerializerReadContextComplexJson context, XmlDictionaryString emptyDictionaryString, XmlDictionaryString itemName, CollectionDataContract collectionContract)
+ {
+ #region GenerateCollectionReaderHelper
+ // InitArgs()
+ this.xmlReader = xmlReader;
+ this.context = context;
+ this.emptyDictionaryString = emptyDictionaryString;
+ this.itemName = itemName;
+
+ this.collectionContract = collectionContract;
+
+ #endregion
+
+ ReadCollection (collectionContract);
+
+ return objectLocal;
+ }
+
+ public void ReadGetOnlyCollectionFromJson (XmlReaderDelegator xmlReader, XmlObjectSerializerReadContextComplexJson context, XmlDictionaryString emptyDictionaryString, XmlDictionaryString itemName, CollectionDataContract collectionContract)
+ {
+ #region GenerateCollectionReaderHelper
+ // InitArgs()
+ this.xmlReader = xmlReader;
+ this.context = context;
+ this.emptyDictionaryString = emptyDictionaryString;
+ this.itemName = itemName;
+
+ this.collectionContract = collectionContract;
+
+ #endregion
+
+ ReadGetOnlyCollection (collectionContract);
+ }
+
+ void CreateObject (ClassDataContract classContract)
+ {
+ Type type = objectType = classContract.UnderlyingType;
+ if (type.IsValueType && !classContract.IsNonAttributedType)
+ type = Globals.TypeOfValueType;
+
+ if (classContract.UnderlyingType == Globals.TypeOfDBNull)
+ objectLocal = DBNull.Value;
+ else if (classContract.IsNonAttributedType) {
+ if (type.IsValueType)
+ objectLocal = FormatterServices.GetUninitializedObject (type);
+ else
+ objectLocal = classContract.GetNonAttributedTypeConstructor ().Invoke (new object [0]);
+ }
+ else
+ objectLocal = CodeInterpreter.ConvertValue (XmlFormatReaderGenerator.UnsafeGetUninitializedObject (DataContract.GetIdForInitialization (classContract)), Globals.TypeOfObject, type);
+ }
+
+ void InvokeOnDeserializing (ClassDataContract classContract)
+ {
+ if (classContract.BaseContract != null)
+ InvokeOnDeserializing (classContract.BaseContract);
+ if (classContract.OnDeserializing != null)
+ classContract.OnDeserializing.Invoke (objectLocal, new object [] {context.GetStreamingContext ()});
+ }
+
+ void InvokeOnDeserialized (ClassDataContract classContract)
+ {
+ if (classContract.BaseContract != null)
+ InvokeOnDeserialized (classContract.BaseContract);
+ if (classContract.OnDeserialized != null)
+ classContract.OnDeserialized.Invoke (objectLocal, new object [] {context.GetStreamingContext ()});
+ }
+
+ bool HasFactoryMethod (ClassDataContract classContract)
+ {
+ return Globals.TypeOfIObjectReference.IsAssignableFrom (classContract.UnderlyingType);
+ }
+
+ bool InvokeFactoryMethod (ClassDataContract classContract)
+ {
+ if (HasFactoryMethod (classContract)) {
+ objectLocal = CodeInterpreter.ConvertValue (context.GetRealObject ((IObjectReference) objectLocal, Globals.NewObjectId), Globals.TypeOfObject, classContract.UnderlyingType);
+ return true;
+ }
+ return false;
+ }
+
+ void ReadISerializable (ClassDataContract classContract)
+ {
+ ConstructorInfo ctor = classContract.UnderlyingType.GetConstructor (Globals.ScanAllMembers, null, JsonFormatGeneratorStatics.SerInfoCtorArgs, null);
+ if (ctor == null)
+ throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError (XmlObjectSerializer.CreateSerializationException (SR.GetString (SR.SerializationInfo_ConstructorNotFound, DataContract.GetClrTypeFullName (classContract.UnderlyingType))));
+ context.ReadSerializationInfo (xmlReader, classContract.UnderlyingType);
+ ctor.Invoke (objectLocal, new object [] {context.GetStreamingContext ()});
+ }
+
+ void ReadClass (ClassDataContract classContract)
+ {
+ if (classContract.HasExtensionData) {
+ ExtensionDataObject extensionData = new ExtensionDataObject ();
+ ReadMembers (classContract, extensionData);
+ ClassDataContract currentContract = classContract;
+ while (currentContract != null) {
+ MethodInfo extensionDataSetMethod = currentContract.ExtensionDataSetMethod;
+ if (extensionDataSetMethod != null)
+ extensionDataSetMethod.Invoke (objectLocal, new object [] {extensionData});
+ currentContract = currentContract.BaseContract;
+ }
+ }
+ else
+ ReadMembers (classContract, null);
+ }
+
+ void ReadMembers (ClassDataContract classContract, ExtensionDataObject extensionData)
+ {
+ int memberCount = classContract.MemberNames.Length;
+ context.IncrementItemCount (memberCount);
+
+ int memberIndex = -1;
+
+ // JSON intrinsic part.
+ BitFlagsGenerator expectedElements = new BitFlagsGenerator (memberCount);
+ byte [] requiredElements = new byte [expectedElements.GetLocalCount ()];
+ SetRequiredElements (classContract, requiredElements);
+ SetExpectedElements (expectedElements, 0 /*startIndex*/);
+
+ while (XmlObjectSerializerReadContext.MoveToNextElement (xmlReader)) {
+ int idx; // used as in "switch (idx)" in the original source.
+ idx = context.GetJsonMemberIndex (xmlReader, memberNames, memberIndex, extensionData);
+
+ if (memberCount > 0)
+ ReadMembers (idx, classContract, expectedElements, ref memberIndex);
+ }
+
+ if (!CheckRequiredElements (expectedElements, requiredElements))
+ XmlObjectSerializerReadContextComplexJson.ThrowMissingRequiredMembers (objectLocal, memberNames, expectedElements.LoadArray (), requiredElements);
+ }
+
+ int ReadMembers (int index, ClassDataContract classContract, BitFlagsGenerator expectedElements, ref int memberIndex)
+ {
+ int memberCount = (classContract.BaseContract == null) ? 0 : ReadMembers (index, classContract.BaseContract, expectedElements,
+ ref memberIndex);
+
+ if (memberCount <= index && index < memberCount + classContract.Members.Count) {
+ DataMember dataMember = classContract.Members [index - memberCount];
+ Type memberType = dataMember.MemberType;
+
+ memberIndex = memberCount;
+ if (!expectedElements.Load (memberCount))
+ XmlObjectSerializerReadContextComplexJson.ThrowDuplicateMemberException (objectLocal, memberNames, memberIndex);
+
+ if (dataMember.IsGetOnlyCollection) {
+ var value = CodeInterpreter.GetMember (dataMember.MemberInfo, objectLocal);
+ context.StoreCollectionMemberInfo (value);
+ ReadValue (memberType, dataMember.Name);
+ } else {
+ var value = ReadValue (memberType, dataMember.Name);
+ CodeInterpreter.SetMember (dataMember.MemberInfo, objectLocal, value);
+ }
+ memberIndex = index;
+ ResetExpectedElements(expectedElements, index);
+ }
+ return memberCount + classContract.Members.Count;
+ }
+
+ bool CheckRequiredElements (BitFlagsGenerator expectedElements, byte [] requiredElements)
+ {
+ for (int i = 0; i < requiredElements.Length; i++)
+ if ((expectedElements.GetLocal(i) & requiredElements[i]) != 0)
+ return false;
+ return true;
+ }
+
+ int SetRequiredElements (ClassDataContract contract, byte [] requiredElements)
+ {
+ int memberCount = (contract.BaseContract == null) ? 0 :
+ SetRequiredElements (contract.BaseContract, requiredElements);
+ List<DataMember> members = contract.Members;
+ for (int i = 0; i < members.Count; i++, memberCount++) {
+ if (members[i].IsRequired)
+ BitFlagsGenerator.SetBit (requiredElements, memberCount);
+ }
+ return memberCount;
+ }
+
+ void SetExpectedElements (BitFlagsGenerator expectedElements, int startIndex)
+ {
+ int memberCount = expectedElements.GetBitCount ();
+ for (int i = startIndex; i < memberCount; i++)
+ expectedElements.Store (i, true);
+ }
+
+ void ResetExpectedElements (BitFlagsGenerator expectedElements, int index)
+ {
+ expectedElements.Store (index, false);
+ }
+
+ object ReadValue (Type type, string name)
+ {
+ var valueType = type;
+ object value = null;
+ bool shouldAssignNullableValue = false;
+ int nullables = 0;
+ while (type.IsGenericType && type.GetGenericTypeDefinition () == Globals.TypeOfNullable) {
+ nullables++;
+ type = type.GetGenericArguments () [0];
+ }
+
+ PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract (type);
+ if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType) {
+ context.ReadAttributes (xmlReader);
+ string objectId = context.ReadIfNullOrRef (xmlReader, type, DataContract.IsTypeSerializable (type));
+ // Deserialize null
+ if (objectId == Globals.NullObjectId) {
+
+ if (nullables != 0)
+ value = Activator.CreateInstance (valueType);
+ else if (type.IsValueType)
+ throw new SerializationException (SR.GetString (SR.ValueTypeCannotBeNull, DataContract.GetClrTypeFullName (type)));
+ else
+ value = null;
+ } else if (objectId == string.Empty) {
+ // Deserialize value
+
+ // Compare against Globals.NewObjectId, which is set to string.Empty
+
+ objectId = context.GetObjectId ();
+
+ if (type.IsValueType) {
+ if (!string.IsNullOrEmpty (objectId))
+ throw new SerializationException (SR.GetString (SR.ValueTypeCannotHaveId, DataContract.GetClrTypeFullName(type)));
+ }
+ object innerValueRead = null;
+ if (nullables != 0)
+ shouldAssignNullableValue = true;
+
+ if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) {
+ value = primitiveContract.XmlFormatReaderMethod.Invoke (xmlReader, new object [0]);
+ if (!type.IsValueType)
+ context.AddNewObject (value);
+ }
+ else
+ value = InternalDeserialize (type, name);
+ } else {
+ // Deserialize ref
+ if (type.IsValueType)
+ throw new SerializationException (SR.GetString (SR.ValueTypeCannotHaveRef, DataContract.GetClrTypeFullName (type)));
+ else
+ value = CodeInterpreter.ConvertValue (context.GetExistingObject (objectId, type, name, string.Empty), Globals.TypeOfObject, type);
+ }
+
+ if (shouldAssignNullableValue) {
+ if (objectId != Globals.NullObjectId)
+ value = WrapNullableObject (type, value, valueType, nullables);
+ }
+ }
+ else
+ value = InternalDeserialize (type, name);
+
+ return value;
+ }
+
+ object InternalDeserialize (Type type, string name)
+ {
+ Type declaredType = type.IsPointer ? Globals.TypeOfReflectionPointer : type;
+ var obj = context.InternalDeserialize (xmlReader, DataContract.GetId (declaredType.TypeHandle), declaredType.TypeHandle, name, string.Empty);
+
+ if (type.IsPointer)
+ // wow, there is no way to convert void* to object in strongly typed way...
+ return JsonFormatGeneratorStatics.UnboxPointer.Invoke (null, new object [] {obj});
+ else
+ return CodeInterpreter.ConvertValue (obj, Globals.TypeOfObject, type);
+ }
+
+ object WrapNullableObject (Type innerType, object innerValue, Type outerType, int nullables)
+ {
+ var outerValue = innerValue;
+ for (int i = 1; i < nullables; i++) {
+ Type type = Globals.TypeOfNullable.MakeGenericType (innerType);
+ outerValue = Activator.CreateInstance (type, new object[] { outerValue });
+ innerType = type;
+ }
+ return Activator.CreateInstance (outerType, new object[] { outerValue });
+ }
+
+
+ void ReadCollection (CollectionDataContract collectionContract)
+ {
+ Type type = collectionContract.UnderlyingType;
+ Type itemType = collectionContract.ItemType;
+ bool isArray = (collectionContract.Kind == CollectionKind.Array);
+
+ ConstructorInfo constructor = collectionContract.Constructor;
+
+ if (type.IsInterface) {
+ switch (collectionContract.Kind) {
+ case CollectionKind.GenericDictionary:
+ type = Globals.TypeOfDictionaryGeneric.MakeGenericType (itemType.GetGenericArguments ());
+ constructor = type.GetConstructor (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Globals.EmptyTypeArray, null);
+ break;
+ case CollectionKind.Dictionary:
+ type = Globals.TypeOfHashtable;
+ constructor = type.GetConstructor (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Globals.EmptyTypeArray, null);
+ break;
+ case CollectionKind.Collection:
+ case CollectionKind.GenericCollection:
+ case CollectionKind.Enumerable:
+ case CollectionKind.GenericEnumerable:
+ case CollectionKind.List:
+ case CollectionKind.GenericList:
+ type = itemType.MakeArrayType ();
+ isArray = true;
+ break;
+ }
+ }
+
+ if (!isArray) {
+ if (type.IsValueType)
+ // FIXME: this is not what the original code does.
+ objectLocal = FormatterServices.GetUninitializedObject (type);
+ else {
+ objectLocal = constructor.Invoke (new object [0]);
+ context.AddNewObject (objectLocal);
+ }
+ }
+
+ bool canReadSimpleDictionary = collectionContract.Kind == CollectionKind.Dictionary ||
+ collectionContract.Kind == CollectionKind.GenericDictionary;
+
+ if (canReadSimpleDictionary & context.UseSimpleDictionaryFormat)
+ ReadSimpleDictionary (collectionContract, itemType);
+ else {
+ string objectId = context.GetObjectId ();
+
+ bool canReadPrimitiveArray = false, readResult = false;
+ if (isArray && TryReadPrimitiveArray (itemType, out readResult))
+ canReadPrimitiveArray = true;
+
+ if (!readResult) {
+ object growingCollection = null;
+ if (isArray)
+ growingCollection = Array.CreateInstance (itemType, 32);
+
+ int i = 0;
+ // FIXME: I cannot find i++ part, but without that it won't work as expected.
+ for (; i < int.MaxValue; i++) {
+ if (IsStartElement (this.itemName, this.emptyDictionaryString)) {
+ context.IncrementItemCount (1);
+ object value = ReadCollectionItem (collectionContract, itemType);
+ if (isArray) {
+ MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod (itemType);
+ growingCollection = ensureArraySizeMethod.Invoke (null, new object [] {growingCollection, i});
+ ((Array) growingCollection).SetValue (value, i);
+ } else {
+ StoreCollectionValue (objectLocal, itemType, value, collectionContract);
+ }
+ }
+ else if (IsEndElement ())
+ break;
+ else
+ HandleUnexpectedItemInCollection (ref i);
+ }
+
+ if (isArray) {
+ MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod (itemType);
+ objectLocal = trimArraySizeMethod.Invoke (null, new object [] {growingCollection, i});
+ context.AddNewObjectWithId (objectId, objectLocal);
+ }
+ }
+ if (canReadPrimitiveArray)
+ context.AddNewObjectWithId (objectId, objectLocal);
+ }
+ }
+
+ void ReadSimpleDictionary (CollectionDataContract collectionContract, Type keyValueType)
+ {
+ Type[] keyValueTypes = keyValueType.GetGenericArguments ();
+ Type keyType = keyValueTypes [0];
+ Type valueType = keyValueTypes [1];
+
+ int keyTypeNullableDepth = 0;
+ Type keyTypeOriginal = keyType;
+ while (keyType.IsGenericType && keyType.GetGenericTypeDefinition () == Globals.TypeOfNullable) {
+ keyTypeNullableDepth++;
+ keyType = keyType.GetGenericArguments () [0];
+ }
+
+ ClassDataContract keyValueDataContract = (ClassDataContract)collectionContract.ItemContract;
+ DataContract keyDataContract = keyValueDataContract.Members [0].MemberTypeContract;
+
+ KeyParseMode keyParseMode = KeyParseMode.Fail;
+
+ if (keyType == Globals.TypeOfString || keyType == Globals.TypeOfObject) {
+ keyParseMode = KeyParseMode.AsString;
+ } else if (keyType.IsEnum) {
+ keyParseMode = KeyParseMode.UsingParseEnum;
+ } else if (keyDataContract.ParseMethod != null) {
+ keyParseMode = KeyParseMode.UsingCustomParse;
+ }
+
+ if (keyParseMode == KeyParseMode.Fail) {
+ ThrowSerializationException (
+ SR.GetString (
+ SR.KeyTypeCannotBeParsedInSimpleDictionary,
+ DataContract.GetClrTypeFullName (collectionContract.UnderlyingType),
+ DataContract.GetClrTypeFullName (keyType)));
+ } else {
+ XmlNodeType nodeType;
+
+ while ((nodeType = xmlReader.MoveToContent ()) != XmlNodeType.EndElement) {
+ if (nodeType != XmlNodeType.Element)
+ ThrowUnexpectedStateException (XmlNodeType.Element);
+
+ context.IncrementItemCount (1);
+
+ var jsonMemberName = XmlObjectSerializerReadContextComplexJson.GetJsonMemberName (xmlReader);
+ object key = null;
+
+ if (keyParseMode == KeyParseMode.UsingParseEnum)
+ key = Enum.Parse (keyType, jsonMemberName);
+ else if (keyParseMode == KeyParseMode.UsingCustomParse)
+ key = keyDataContract.ParseMethod.Invoke (null, new object [] {jsonMemberName});
+
+ if (keyTypeNullableDepth > 0) {
+ var keyOriginal = WrapNullableObject (keyType, key, valueType, keyTypeNullableDepth);
+ key = keyOriginal;
+ }
+
+ var value = ReadValue (valueType, String.Empty);
+ collectionContract.AddMethod.Invoke (objectLocal, new object[] {key, value});
+ }
+ }
+ }
+
+ // CONTINUE FROM HERE
+
+ void ReadGetOnlyCollection (CollectionDataContract collectionContract)
+ {
+ Type type = collectionContract.UnderlyingType;
+ Type itemType = collectionContract.ItemType;
+ bool isArray = (collectionContract.Kind == CollectionKind.Array);
+ int size = 0;
+
+ objectLocal = context.GetCollectionMember ();
+
+ bool canReadSimpleDictionary =
+ collectionContract.Kind == CollectionKind.Dictionary ||
+ collectionContract.Kind == CollectionKind.GenericDictionary;
+
+ bool readSimple = canReadSimpleDictionary && context.UseSimpleDictionaryFormat;
+ if (readSimple) {
+ if (objectLocal == null)
+ XmlObjectSerializerReadContext.ThrowNullValueReturnedForGetOnlyCollectionException (type);
+ else {
+ ReadSimpleDictionary(collectionContract, itemType);
+ context.CheckEndOfArray (xmlReader, size, this.itemName, emptyDictionaryString);
+ }
+ } else {
+
+ //check that items are actually going to be deserialized into the collection
+ if (IsStartElement (this.itemName, this.emptyDictionaryString)) {
+ if (objectLocal == null)
+ XmlObjectSerializerReadContext.ThrowNullValueReturnedForGetOnlyCollectionException (type);
+ else {
+ size = 0;
+ if (isArray)
+ size = ((Array) objectLocal).Length;
+ for (int i = 0; i < int.MaxValue;) {
+ if (IsStartElement (this.itemName, this.emptyDictionaryString)) {
+ context.IncrementItemCount (1);
+ var value = ReadCollectionItem (collectionContract, itemType);
+ if (isArray) {
+ if (size == i)
+ XmlObjectSerializerReadContext.ThrowArrayExceededSizeException (size, type);
+ else
+ ((Array) objectLocal).SetValue (value, i);
+ } else {
+ StoreCollectionValue (objectLocal, itemType, value, collectionContract);
+ }
+ }
+ else if (IsEndElement())
+ break;
+ else
+ HandleUnexpectedItemInCollection (ref i);
+ }
+ context.CheckEndOfArray (xmlReader, size, this.itemName, this.emptyDictionaryString);
+ }
+ }
+ }
+ }
+
+ bool TryReadPrimitiveArray (Type itemType, out bool readResult)
+ {
+ readResult = false;
+ PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract (itemType);
+ if (primitiveContract == null)
+ return false;
+
+ string readArrayMethod = null;
+ switch (Type.GetTypeCode (itemType))
+ {
+ case TypeCode.Boolean:
+ readArrayMethod = "TryReadBooleanArray";
+ break;
+ case TypeCode.Decimal:
+ readArrayMethod = "TryReadDecimalArray";
+ break;
+ case TypeCode.Int32:
+ readArrayMethod = "TryReadInt32Array";
+ break;
+ case TypeCode.Int64:
+ readArrayMethod = "TryReadInt64Array";
+ break;
+ case TypeCode.Single:
+ readArrayMethod = "TryReadSingleArray";
+ break;
+ case TypeCode.Double:
+ readArrayMethod = "TryReadDoubleArray";
+ break;
+ case TypeCode.DateTime:
+ readArrayMethod = "TryReadJsonDateTimeArray";
+ break;
+ default:
+ break;
+ }
+ if (readArrayMethod != null) {
+ var mi = typeof (JsonReaderDelegator).GetMethod (readArrayMethod, Globals.ScanAllMembers);
+ var args = new object [] {context, itemName, emptyDictionaryString, -1, objectLocal};
+ readResult = (bool) mi.Invoke ((JsonReaderDelegator) xmlReader, args);
+ objectLocal = args.Last ();
+ return true;
+ }
+ return false;
+ }
+
+ object ReadCollectionItem (CollectionDataContract collectionContract, Type itemType)
+ {
+ if (collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary) {
+ context.ResetAttributes ();
+ var v = DataContractJsonSerializer.ReadJsonValue (XmlObjectSerializerWriteContextComplexJson.GetRevisedItemContract (collectionContract.ItemContract), xmlReader, context);
+ return CodeInterpreter.ConvertValue (v, Globals.TypeOfObject, itemType);
+ }
+ else
+ return ReadValue (itemType, JsonGlobals.itemString);
+ }
+
+ void StoreCollectionValue (object collection, Type valueType, object value, CollectionDataContract collectionContract)
+ {
+ if (collectionContract.Kind == CollectionKind.GenericDictionary || collectionContract.Kind == CollectionKind.Dictionary) {
+ ClassDataContract keyValuePairContract = DataContract.GetDataContract (valueType) as ClassDataContract;
+ if (keyValuePairContract == null)
+ Fx.Assert ("Failed to create contract for KeyValuePair type");
+ DataMember keyMember = keyValuePairContract.Members [0];
+ DataMember valueMember = keyValuePairContract.Members [1];
+ object pkey = CodeInterpreter.GetMember (keyMember.MemberInfo, value);
+ object pvalue = CodeInterpreter.GetMember (valueMember.MemberInfo, value);
+
+ collectionContract.AddMethod.Invoke (collection, new object [] {pkey, pvalue});
+ }
+ else
+ collectionContract.AddMethod.Invoke (collection, new object [] {value});
+ }
+
+ void HandleUnexpectedItemInCollection (ref int iterator)
+ {
+ if (IsStartElement ()) {
+ context.SkipUnknownElement (xmlReader);
+ iterator--;
+ }
+ else
+ throw XmlObjectSerializerReadContext.CreateUnexpectedStateException (XmlNodeType.Element, xmlReader);
+ }
+
+ bool IsStartElement(XmlDictionaryString name, XmlDictionaryString ns)
+ {
+ return xmlReader.IsStartElement (name, ns);
+ }
+
+ bool IsStartElement()
+ {
+ return xmlReader.IsStartElement ();
+ }
+
+ bool IsEndElement ()
+ {
+ return xmlReader.NodeType == XmlNodeType.EndElement;
+ }
+
+ void ThrowUnexpectedStateException (XmlNodeType expectedState)
+ {
+ throw XmlObjectSerializerReadContext.CreateUnexpectedStateException (expectedState, xmlReader);
+ }
+
+ void ThrowSerializationException (string msg, params object [] values)
+ {
+ if (values != null && values.Length > 0)
+ msg = string.Format (msg, values);
+ throw new SerializationException (msg);
+ }
+
+ enum KeyParseMode
+ {
+ Fail,
+ AsString,
+ UsingParseEnum,
+ UsingCustomParse
+ }
+ }
+}
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
{
internal JsonFormatClassWriterDelegate GenerateClassWriter(ClassDataContract classContract)
{
- throw new NotImplementedException ();
+ return (XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContextComplexJson context, ClassDataContract dataContract, XmlDictionaryString [] memberNames) => new JsonFormatWriterInterpreter (classContract).WriteToJson (xmlWriter, obj, context, dataContract, memberNames);
}
internal JsonFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionDataContract collectionContract)
{
- throw new NotImplementedException ();
+ return (XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContextComplexJson context, CollectionDataContract dataContract) => new JsonFormatWriterInterpreter (collectionContract).WriteCollectionToJson (xmlWriter, obj, context, dataContract);
}
}
}
+
+ class JsonFormatWriterInterpreter
+ {
+ public JsonFormatWriterInterpreter (ClassDataContract classContract)
+ {
+ this.classContract = classContract;
+ }
+
+ public JsonFormatWriterInterpreter (CollectionDataContract collectionContract)
+ {
+ this.collectionContract = collectionContract;
+ }
+
+ ClassDataContract classContract;
+
+ CollectionDataContract collectionContract;
+
+ XmlWriterDelegator writer = null;
+ object obj = null;
+ XmlObjectSerializerWriteContextComplexJson context = null;
+ DataContract dataContract = null;
+ object objLocal = null;
+
+ ClassDataContract classDataContract {
+ get { return (ClassDataContract) dataContract; }
+ }
+ CollectionDataContract collectionDataContract {
+ get {return (CollectionDataContract) dataContract; }
+ }
+
+ XmlDictionaryString [] memberNames = null;
+ int typeIndex = 1;
+ int childElementIndex = 0;
+
+ public void WriteToJson (XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContextComplexJson context, ClassDataContract dataContract, XmlDictionaryString [] memberNames)
+ {
+ this.writer = xmlWriter;
+ this.obj = obj;
+ this.context = context;
+ this.dataContract = dataContract;
+ this.memberNames = memberNames;
+
+ InitArgs (classContract.UnderlyingType);
+
+ // DemandSerializationFormatterPermission (classContract) - irrelevant
+ // DemandMemberAccessPermission (memberAccessFlag) - irrelevant
+
+ if (classContract.IsReadOnlyContract)
+ {
+ DataContract.ThrowInvalidDataContractException (classContract.SerializationExceptionMessage, null);
+ }
+
+ WriteClass (classContract);
+ }
+
+ public void WriteCollectionToJson (XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContextComplexJson context, CollectionDataContract dataContract)
+ {
+ this.writer = xmlWriter;
+ this.obj = obj;
+ this.context = context;
+ this.dataContract = dataContract;
+
+ 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 context)
+ {
+ if (classContract.BaseContract != null)
+ InvokeOnSerializing (classContract.BaseContract, objSerialized, context);
+ if (classContract.OnSerializing != null) {
+ classContract.OnSerializing.Invoke (objSerialized, new object [] {context.GetStreamingContext ()});
+ }
+ }
+
+ void InvokeOnSerialized (ClassDataContract classContract, object objSerialized, XmlObjectSerializerWriteContext context)
+ {
+ if (classContract.BaseContract != null)
+ InvokeOnSerialized (classContract.BaseContract, objSerialized, context);
+ if (classContract.OnSerialized != null) {
+ classContract.OnSerialized.Invoke (objSerialized, new object [] {context.GetStreamingContext ()});
+ }
+ }
+
+ void WriteClass (ClassDataContract classContract)
+ {
+ InvokeOnSerializing (classContract, objLocal, context);
+
+ if (classContract.IsISerializable)
+ context.WriteJsonISerializable (writer, (ISerializable) objLocal);
+ else
+ {
+ if (classContract.HasExtensionData)
+ {
+ ExtensionDataObject extensionData = ((IExtensibleDataObject) objLocal).ExtensionData;
+ context.WriteExtensionData (writer, extensionData, -1);
+
+ WriteMembers (classContract, extensionData, classContract);
+ }
+ else
+ WriteMembers (classContract, null, classContract);
+ }
+ InvokeOnSerialized (classContract, objLocal, context);
+ }
+
+ void WriteCollection(CollectionDataContract collectionContract)
+ {
+ XmlDictionaryString itemName = context.CollectionItemName;
+
+ if (collectionContract.Kind == CollectionKind.Array)
+ {
+ Type itemType = collectionContract.ItemType;
+ int i;
+
+ // This check does not exist in the original dynamic code,
+ // but there is no other way to check type mismatch.
+ // CollectionSerialization.ArrayContract() shows that it is required.
+ if (objLocal.GetType ().GetElementType () != itemType)
+ throw new InvalidCastException (string.Format ("Cannot cast array of {0} to array of {1}", objLocal.GetType ().GetElementType (), itemType));
+
+ context.IncrementArrayCount (writer, (Array) objLocal);
+
+ if (!TryWritePrimitiveArray(collectionContract.UnderlyingType, itemType, () => objLocal, itemName))
+ {
+ WriteArrayAttribute ();
+ var arr = (Array) objLocal;
+ var idx = new int [1];
+ for (i = 0; i < arr.Length; i++) {
+ if (!TryWritePrimitive(itemType, null, null, i, itemName, 0)) {
+ WriteStartElement (itemName, 0);
+ idx [0] = i;
+ var mbrVal = arr.GetValue (idx);
+ WriteValue (itemType, mbrVal);
+ WriteEndElement ();
+ }
+ }
+ }
+ }
+ else
+ {
+ // This check does not exist in the original dynamic code,
+ // but there is no other way to check type mismatch.
+ // CollectionSerialization.ArrayContract() shows that it is required.
+ if (!collectionContract.UnderlyingType.IsAssignableFrom (objLocal.GetType ()))
+ throw new InvalidCastException (string.Format ("Cannot cast {0} to {1}", objLocal.GetType (), collectionContract.UnderlyingType));
+
+ 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 (context, 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 = JsonFormatGeneratorStatics.MoveNextMethod;
+ if (getCurrentMethod == null)
+ getCurrentMethod = JsonFormatGeneratorStatics.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
+
+ var enumerator = (IEnumerator) collectionContract.GetEnumeratorMethod.Invoke (objLocal, new object [0]);
+ if (isDictionary)
+ {
+ ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor (Globals.ScanAllMembers, null, new Type[] { Globals.TypeOfIDictionaryEnumerator }, null);
+ enumerator = (IEnumerator) dictEnumCtor.Invoke (new object [] {enumerator});
+ }
+ 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 [] {enumerator});
+ }
+
+ bool canWriteSimpleDictionary = isDictionary || isGenericDictionary;
+
+ bool writeSimpleDictionary = canWriteSimpleDictionary | context.UseSimpleDictionaryFormat;
+ PropertyInfo genericDictionaryKeyProperty = null, genericDictionaryValueProperty = null;
+
+ if (canWriteSimpleDictionary)
+ {
+ Type genericDictionaryKeyValueType = Globals.TypeOfKeyValue.MakeGenericType (keyValueTypes);
+ genericDictionaryKeyProperty = genericDictionaryKeyValueType.GetProperty (JsonGlobals.KeyString);
+ genericDictionaryValueProperty = genericDictionaryKeyValueType.GetProperty (JsonGlobals.ValueString);
+ }
+
+ if (writeSimpleDictionary) {
+ WriteObjectAttribute ();
+ object key, value;
+ var empty_args = new object [0];
+ while ((bool) moveNextMethod.Invoke (enumerator, empty_args)) {
+ currentValue = getCurrentMethod.Invoke (enumerator, empty_args);
+ key = CodeInterpreter.GetMember (genericDictionaryKeyProperty, currentValue);
+ value = CodeInterpreter.GetMember (genericDictionaryValueProperty, currentValue);
+
+ WriteStartElement (key, 0 /*nameIndex*/);
+ WriteValue (genericDictionaryValueProperty.PropertyType, value);
+ WriteEndElement ();
+ }
+ } else {
+ WriteArrayAttribute ();
+
+ var emptyArray = new object [0];
+ while (enumerator != null && enumerator.MoveNext ()) {
+ currentValue = getCurrentMethod.Invoke (enumerator, emptyArray);
+
+ if (incrementCollectionCountMethod == null)
+ XmlFormatGeneratorStatics.IncrementItemCountMethod.Invoke (context, new object [] {1});
+
+ if (!TryWritePrimitive (elementType, () => currentValue, null, null, itemName, 0))
+ {
+ WriteStartElement (itemName, 0);
+ if (isGenericDictionary || isDictionary) {
+ var jc = JsonDataContract.GetJsonDataContract (XmlObjectSerializerWriteContextComplexJson.GetRevisedItemContract (
+ collectionDataContract.ItemContract));
+ // FIXME: this TypeHandle might be wrong; there is no easy way to get Type for currentValue though.
+ DataContractJsonSerializer.WriteJsonValue (jc, writer, currentValue, context, currentValue.GetType ().TypeHandle);
+ }
+ else
+ WriteValue (elementType, currentValue);
+ WriteEndElement ();
+ }
+ }
+ }
+ }
+ }
+
+ int WriteMembers (ClassDataContract classContract, ExtensionDataObject extensionData, ClassDataContract derivedMostClassContract)
+ {
+ int memberCount = (classContract.BaseContract == null) ? 0 : WriteMembers (classContract.BaseContract, extensionData, derivedMostClassContract);
+
+ context.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)
+ context.StoreIsGetOnlyCollection ();
+ bool doWrite = true, hasMemberValue = false;
+ if (!member.EmitDefaultValue)
+ {
+ hasMemberValue = true;
+ memberValue = LoadMemberValue (member);
+ doWrite = !IsDefaultValue (memberType, memberValue);
+ }
+
+ if (doWrite) {
+
+ bool requiresNameAttribute = DataContractJsonSerializer.CheckIfXmlNameRequiresMapping (classContract.MemberNames [i]);
+
+ if (requiresNameAttribute || !TryWritePrimitive(memberType, hasMemberValue ? () => memberValue : (Func<object>) null, member.MemberInfo, null /*arrayItemIndex*/, null /*nameLocal*/, i + childElementIndex)) {
+
+ // Note: DataContractSerializer has member-conflict logic here to deal with the schema export
+ // requirement that the same member can't be of two different types.
+ if (requiresNameAttribute)
+ XmlObjectSerializerWriteContextComplexJson.WriteJsonNameWithMapping (writer, memberNames, i + childElementIndex);
+ else
+ WriteStartElement (null /*nameLocal*/, i + childElementIndex);
+
+ if (memberValue == null)
+ memberValue = LoadMemberValue (member);
+ WriteValue (memberType, memberValue);
+ WriteEndElement ();
+ }
+
+ if (classContract.HasExtensionData)
+ context.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;
+ }
+
+ void WriteStartElement (object nameLocal, int nameIndex)
+ {
+ var name = nameLocal ?? memberNames [nameIndex];
+ XmlDictionaryString namespaceLocal = null;
+ if (nameLocal != null && nameLocal is string)
+ writer.WriteStartElement ((string) name, null);
+ else
+ writer.WriteStartElement ((XmlDictionaryString) name, null);
+ }
+
+ void WriteEndElement ()
+ {
+ writer.WriteEndElement ();
+ }
+
+ void WriteArrayAttribute ()
+ {
+ writer.WriteAttributeString (
+ null /* prefix */,
+ JsonGlobals.typeString /* local name */,
+ string.Empty /* namespace */,
+ JsonGlobals.arrayString /* value */);
+ }
+
+ void WriteObjectAttribute ()
+ {
+ writer.WriteAttributeString (
+ null /* prefix */,
+ JsonGlobals.typeString /* local name */,
+ null /* namespace */,
+ JsonGlobals.objectString /* value */);
+ }
+
+ void WriteValue (Type memberType, object memberValue)
+ {
+ Pointer memberValueRefPointer = null;
+ if (memberType.IsPointer)
+ memberValueRefPointer = (Pointer) JsonFormatGeneratorStatics.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)
+ primitiveContract.XmlFormatContentWriterMethod.Invoke (writer, new object [] {memberValue});
+ else
+ InternalSerialize (XmlFormatGeneratorStatics.InternalSerializeMethod, () => memberValue, memberType, false);
+ }
+ 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 (context, new object [] {writer, memberType, DataContract.IsTypeSerializable(memberType)});
+ else {
+ PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
+ if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) {
+ if (isNullableOfT)
+ primitiveContract.XmlFormatContentWriterMethod.Invoke (writer, new object [] {memberValue});
+ else
+ primitiveContract.XmlFormatContentWriterMethod.Invoke (context, 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;
+ isNull2 = memberValue == null;
+ }
+ if (isNull2) {
+ XmlFormatGeneratorStatics.WriteNullMethod.Invoke (context, new object [] {writer, memberType, DataContract.IsTypeSerializable(memberType)});
+ } else {
+ InternalSerialize((isNullableOfT ? XmlFormatGeneratorStatics.InternalSerializeMethod : XmlFormatGeneratorStatics.InternalSerializeReferenceMethod),
+ () => memberValue, memberType, false);
+ }
+ }
+ }
+ }
+ }
+
+ void InternalSerialize (MethodInfo methodInfo, Func<object> memberValue, Type memberType, bool writeXsiType)
+ {
+ var v = memberValue ();
+ var typeHandleValue = Type.GetTypeHandle (v);
+ var isDeclaredType = typeHandleValue.Equals (CodeInterpreter.ConvertValue (v, memberType, Globals.TypeOfObject));
+ methodInfo.Invoke (context, new object [] {writer, memberValue != null ? v : 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 v = memberValue ();
+ isNull = false;
+ while (memberType.IsGenericType && memberType.GetGenericTypeDefinition () == Globals.TypeOfNullable) {
+ Type innerType = memberType.GetGenericArguments () [0];
+ if ((bool) XmlFormatGeneratorStatics.GetHasValueMethod.MakeGenericMethod (innerType).Invoke (null, new object [] {v}))
+ v = XmlFormatGeneratorStatics.GetNullableValueMethod.MakeGenericMethod (innerType).Invoke (null, new object [] {v});
+ else {
+ isNull = true;
+ v = XmlFormatGeneratorStatics.GetDefaultValueMethod.MakeGenericMethod (memberType).Invoke (null, new object [0]);
+ }
+ memberType = innerType;
+ }
+
+ return v;
+ }
+
+ bool TryWritePrimitive(Type type, Func<object> value, MemberInfo memberInfo, int? arrayItemIndex, 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 writer
+ if (type.IsValueType)
+ callee = writer;
+ else {
+ callee = context;
+ args.Add (writer);
+ }
+ // load primitive value
+ if (value != null)
+ args.Add (value ());
+ else if (memberInfo != null)
+ args.Add (CodeInterpreter.GetMember (memberInfo, objLocal));
+ else
+ args.Add (((Array) objLocal).GetValue (new int [] {(int) arrayItemIndex}));
+ // load name
+ if (name != null)
+ args.Add (name);
+ else
+ args.Add (memberNames [nameIndex]);
+ // load namespace
+ args.Add (null);
+ // call method to write primitive
+ primitiveContract.XmlFormatWriterMethod.Invoke (callee, args.ToArray ());
+ return true;
+ }
+
+ bool TryWritePrimitiveArray (Type type, Type itemType, Func<object> value, XmlDictionaryString itemName)
+ {
+ PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType);
+ if (primitiveContract == null)
+ return false;
+
+ string writeArrayMethod = null;
+ switch (Type.GetTypeCode(itemType))
+ {
+ case TypeCode.Boolean:
+ writeArrayMethod = "WriteJsonBooleanArray";
+ break;
+ case TypeCode.DateTime:
+ writeArrayMethod = "WriteJsonDateTimeArray";
+ break;
+ case TypeCode.Decimal:
+ writeArrayMethod = "WriteJsonDecimalArray";
+ break;
+ case TypeCode.Int32:
+ writeArrayMethod = "WriteJsonInt32Array";
+ break;
+ case TypeCode.Int64:
+ writeArrayMethod = "WriteJsonInt64Array";
+ break;
+ case TypeCode.Single:
+ writeArrayMethod = "WriteJsonSingleArray";
+ break;
+ case TypeCode.Double:
+ writeArrayMethod = "WriteJsonDoubleArray";
+ break;
+ default:
+ break;
+ }
+ if (writeArrayMethod != null)
+ {
+ WriteArrayAttribute ();
+ typeof(JsonWriterDelegator).GetMethod(writeArrayMethod, Globals.ScanAllMembers, null, new Type[] { type, typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null).Invoke (writer, new object [] {value (), itemName, null});
+ return true;
+ }
+ return false;
+ }
+
+ object LoadMemberValue (DataMember member)
+ {
+ return CodeInterpreter.GetMember (member.MemberInfo, objLocal);
+ }
+ }
}