JsonFormatWriterGenerator_static.cs 23 KB

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