CollectionDataContract.cs 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.Runtime.Serialization
  5. {
  6. using System;
  7. using System.Collections;
  8. using System.Diagnostics;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. using System.Globalization;
  12. using System.Reflection;
  13. using System.Threading;
  14. using System.Xml;
  15. #if !NO_CONFIGURATION
  16. using System.Runtime.Serialization.Configuration;
  17. #endif
  18. using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
  19. using System.Security;
  20. using System.Security.Permissions;
  21. [DataContract(Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
  22. #if USE_REFEMIT
  23. public struct KeyValue<K, V>
  24. #else
  25. internal struct KeyValue<K, V>
  26. #endif
  27. {
  28. K key;
  29. V value;
  30. internal KeyValue(K key, V value)
  31. {
  32. this.key = key;
  33. this.value = value;
  34. }
  35. [DataMember(IsRequired = true)]
  36. public K Key
  37. {
  38. get { return key; }
  39. set { key = value; }
  40. }
  41. [DataMember(IsRequired = true)]
  42. public V Value
  43. {
  44. get { return value; }
  45. set { this.value = value; }
  46. }
  47. }
  48. internal enum CollectionKind : byte
  49. {
  50. None,
  51. GenericDictionary,
  52. Dictionary,
  53. GenericList,
  54. GenericCollection,
  55. List,
  56. GenericEnumerable,
  57. Collection,
  58. Enumerable,
  59. Array,
  60. }
  61. #if USE_REFEMIT
  62. public sealed class CollectionDataContract : DataContract
  63. #else
  64. internal sealed class CollectionDataContract : DataContract
  65. #endif
  66. {
  67. [Fx.Tag.SecurityNote(Critical = "XmlDictionaryString representing the XML element name for collection items."
  68. + "Statically cached and used from IL generated code.")]
  69. [SecurityCritical]
  70. XmlDictionaryString collectionItemName;
  71. [Fx.Tag.SecurityNote(Critical = "XmlDictionaryString representing the XML namespace for collection items."
  72. + "Statically cached and used from IL generated code.")]
  73. [SecurityCritical]
  74. XmlDictionaryString childElementNamespace;
  75. [Fx.Tag.SecurityNote(Critical = "Internal DataContract representing the contract for collection items."
  76. + "Statically cached and used from IL generated code.")]
  77. [SecurityCritical]
  78. DataContract itemContract;
  79. [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that is cached statically for serialization. "
  80. + "Static fields are marked SecurityCritical or readonly to prevent data from being modified or leaked to other components in appdomain.")]
  81. [SecurityCritical]
  82. CollectionDataContractCriticalHelper helper;
  83. [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
  84. Safe = "Doesn't leak anything.")]
  85. [SecuritySafeCritical]
  86. internal CollectionDataContract(CollectionKind kind)
  87. : base(new CollectionDataContractCriticalHelper(kind))
  88. {
  89. InitCollectionDataContract(this);
  90. }
  91. [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
  92. Safe = "Doesn't leak anything.")]
  93. [SecuritySafeCritical]
  94. internal CollectionDataContract(Type type)
  95. : base(new CollectionDataContractCriticalHelper(type))
  96. {
  97. InitCollectionDataContract(this);
  98. }
  99. [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
  100. Safe = "Doesn't leak anything.")]
  101. [SecuritySafeCritical]
  102. internal CollectionDataContract(Type type, DataContract itemContract)
  103. : base(new CollectionDataContractCriticalHelper(type, itemContract))
  104. {
  105. InitCollectionDataContract(this);
  106. }
  107. [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
  108. Safe = "Doesn't leak anything.")]
  109. [SecuritySafeCritical]
  110. CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, string serializationExceptionMessage, string deserializationExceptionMessage)
  111. : base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage))
  112. {
  113. InitCollectionDataContract(GetSharedTypeContract(type));
  114. }
  115. [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
  116. Safe = "Doesn't leak anything.")]
  117. [SecuritySafeCritical]
  118. CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor)
  119. : base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, addMethod, constructor))
  120. {
  121. InitCollectionDataContract(GetSharedTypeContract(type));
  122. }
  123. [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
  124. Safe = "Doesn't leak anything.")]
  125. [SecuritySafeCritical]
  126. CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor, bool isConstructorCheckRequired)
  127. : base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, addMethod, constructor, isConstructorCheckRequired))
  128. {
  129. InitCollectionDataContract(GetSharedTypeContract(type));
  130. }
  131. [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
  132. Safe = "Doesn't leak anything.")]
  133. [SecuritySafeCritical]
  134. CollectionDataContract(Type type, string invalidCollectionInSharedContractMessage)
  135. : base(new CollectionDataContractCriticalHelper(type, invalidCollectionInSharedContractMessage))
  136. {
  137. InitCollectionDataContract(GetSharedTypeContract(type));
  138. }
  139. [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical fields; called from all constructors.")]
  140. [SecurityCritical]
  141. void InitCollectionDataContract(DataContract sharedTypeContract)
  142. {
  143. this.helper = base.Helper as CollectionDataContractCriticalHelper;
  144. this.collectionItemName = helper.CollectionItemName;
  145. if (helper.Kind == CollectionKind.Dictionary || helper.Kind == CollectionKind.GenericDictionary)
  146. {
  147. this.itemContract = helper.ItemContract;
  148. }
  149. this.helper.SharedTypeContract = sharedTypeContract;
  150. }
  151. void InitSharedTypeContract()
  152. {
  153. }
  154. static Type[] KnownInterfaces
  155. {
  156. [Fx.Tag.SecurityNote(Critical = "Fetches the critical knownInterfaces property.",
  157. Safe = "knownInterfaces only needs to be protected for write.")]
  158. [SecuritySafeCritical]
  159. get { return CollectionDataContractCriticalHelper.KnownInterfaces; }
  160. }
  161. internal CollectionKind Kind
  162. {
  163. [Fx.Tag.SecurityNote(Critical = "Fetches the critical kind property.",
  164. Safe = "kind only needs to be protected for write.")]
  165. [SecuritySafeCritical]
  166. get { return helper.Kind; }
  167. }
  168. internal Type ItemType
  169. {
  170. [Fx.Tag.SecurityNote(Critical = "Fetches the critical itemType property.",
  171. Safe = "itemType only needs to be protected for write.")]
  172. [SecuritySafeCritical]
  173. get { return helper.ItemType; }
  174. }
  175. public DataContract ItemContract
  176. {
  177. [Fx.Tag.SecurityNote(Critical = "Fetches the critical itemContract property.",
  178. Safe = "itemContract only needs to be protected for write.")]
  179. [SecuritySafeCritical]
  180. get { return itemContract ?? helper.ItemContract; }
  181. [Fx.Tag.SecurityNote(Critical = "Sets the critical itemContract property.")]
  182. [SecurityCritical]
  183. set
  184. {
  185. itemContract = value;
  186. helper.ItemContract = value;
  187. }
  188. }
  189. internal DataContract SharedTypeContract
  190. {
  191. [Fx.Tag.SecurityNote(Critical = "Fetches the critical sharedTypeContract property.",
  192. Safe = "sharedTypeContract only needs to be protected for write.")]
  193. [SecuritySafeCritical]
  194. get { return helper.SharedTypeContract; }
  195. }
  196. internal string ItemName
  197. {
  198. [Fx.Tag.SecurityNote(Critical = "Fetches the critical itemName property.",
  199. Safe = "itemName only needs to be protected for write.")]
  200. [SecuritySafeCritical]
  201. get { return helper.ItemName; }
  202. [Fx.Tag.SecurityNote(Critical = "Sets the critical itemName property.")]
  203. [SecurityCritical]
  204. set { helper.ItemName = value; }
  205. }
  206. public XmlDictionaryString CollectionItemName
  207. {
  208. [Fx.Tag.SecurityNote(Critical = "Fetches the critical collectionItemName property.",
  209. Safe = "collectionItemName only needs to be protected for write.")]
  210. [SecuritySafeCritical]
  211. get { return this.collectionItemName; }
  212. }
  213. internal string KeyName
  214. {
  215. [Fx.Tag.SecurityNote(Critical = "Fetches the critical keyName property.",
  216. Safe = "keyName only needs to be protected for write.")]
  217. [SecuritySafeCritical]
  218. get { return helper.KeyName; }
  219. [Fx.Tag.SecurityNote(Critical = "Sets the critical keyName property.")]
  220. [SecurityCritical]
  221. set { helper.KeyName = value; }
  222. }
  223. internal string ValueName
  224. {
  225. [Fx.Tag.SecurityNote(Critical = "Fetches the critical valueName property.",
  226. Safe = "valueName only needs to be protected for write.")]
  227. [SecuritySafeCritical]
  228. get { return helper.ValueName; }
  229. [Fx.Tag.SecurityNote(Critical = "Sets the critical valueName property.")]
  230. [SecurityCritical]
  231. set { helper.ValueName = value; }
  232. }
  233. internal bool IsDictionary
  234. {
  235. get { return KeyName != null; }
  236. }
  237. public XmlDictionaryString ChildElementNamespace
  238. {
  239. [Fx.Tag.SecurityNote(Critical = "Fetches the critical childElementNamespace property.",
  240. Safe = "childElementNamespace only needs to be protected for write; initialized in getter if null.")]
  241. [SecuritySafeCritical]
  242. get
  243. {
  244. if (this.childElementNamespace == null)
  245. {
  246. lock (this)
  247. {
  248. if (this.childElementNamespace == null)
  249. {
  250. if (helper.ChildElementNamespace == null && !IsDictionary)
  251. {
  252. XmlDictionaryString tempChildElementNamespace = ClassDataContract.GetChildNamespaceToDeclare(this, ItemType, new XmlDictionary());
  253. Thread.MemoryBarrier();
  254. helper.ChildElementNamespace = tempChildElementNamespace;
  255. }
  256. this.childElementNamespace = helper.ChildElementNamespace;
  257. }
  258. }
  259. }
  260. return childElementNamespace;
  261. }
  262. }
  263. internal bool IsItemTypeNullable
  264. {
  265. [Fx.Tag.SecurityNote(Critical = "Fetches the critical isItemTypeNullable property.",
  266. Safe = "isItemTypeNullable only needs to be protected for write.")]
  267. [SecuritySafeCritical]
  268. get { return helper.IsItemTypeNullable; }
  269. [Fx.Tag.SecurityNote(Critical = "Sets the critical isItemTypeNullable property.")]
  270. [SecurityCritical]
  271. set { helper.IsItemTypeNullable = value; }
  272. }
  273. internal bool IsConstructorCheckRequired
  274. {
  275. [Fx.Tag.SecurityNote(Critical = "Fetches the critical isConstructorCheckRequired property.",
  276. Safe = "isConstructorCheckRequired only needs to be protected for write.")]
  277. [SecuritySafeCritical]
  278. get { return helper.IsConstructorCheckRequired; }
  279. [Fx.Tag.SecurityNote(Critical = "Sets the critical isConstructorCheckRequired property.")]
  280. [SecurityCritical]
  281. set { helper.IsConstructorCheckRequired = value; }
  282. }
  283. internal MethodInfo GetEnumeratorMethod
  284. {
  285. [Fx.Tag.SecurityNote(Critical = "Fetches the critical getEnumeratorMethod property.",
  286. Safe = "getEnumeratorMethod only needs to be protected for write.")]
  287. [SecuritySafeCritical]
  288. get { return helper.GetEnumeratorMethod; }
  289. }
  290. internal MethodInfo AddMethod
  291. {
  292. [Fx.Tag.SecurityNote(Critical = "Fetches the critical addMethod property.",
  293. Safe = "addMethod only needs to be protected for write.")]
  294. [SecuritySafeCritical]
  295. get { return helper.AddMethod; }
  296. }
  297. internal ConstructorInfo Constructor
  298. {
  299. [Fx.Tag.SecurityNote(Critical = "Fetches the critical constructor property.",
  300. Safe = "constructor only needs to be protected for write.")]
  301. [SecuritySafeCritical]
  302. get { return helper.Constructor; }
  303. }
  304. internal override DataContractDictionary KnownDataContracts
  305. {
  306. [Fx.Tag.SecurityNote(Critical = "Fetches the critical knownDataContracts property.",
  307. Safe = "knownDataContracts only needs to be protected for write.")]
  308. [SecuritySafeCritical]
  309. get { return helper.KnownDataContracts; }
  310. [Fx.Tag.SecurityNote(Critical = "Sets the critical knownDataContracts property.")]
  311. [SecurityCritical]
  312. set { helper.KnownDataContracts = value; }
  313. }
  314. internal string InvalidCollectionInSharedContractMessage
  315. {
  316. [Fx.Tag.SecurityNote(Critical = "Fetches the critical invalidCollectionInSharedContractMessage property.",
  317. Safe = "invalidCollectionInSharedContractMessage only needs to be protected for write.")]
  318. [SecuritySafeCritical]
  319. get { return helper.InvalidCollectionInSharedContractMessage; }
  320. }
  321. internal string SerializationExceptionMessage
  322. {
  323. [Fx.Tag.SecurityNote(Critical = "Fetches the critical serializationExceptionMessage property.",
  324. Safe = "serializationExceptionMessage only needs to be protected for write.")]
  325. [SecuritySafeCritical]
  326. get { return helper.SerializationExceptionMessage; }
  327. }
  328. internal string DeserializationExceptionMessage
  329. {
  330. [Fx.Tag.SecurityNote(Critical = "Fetches the critical deserializationExceptionMessage property.",
  331. Safe = "deserializationExceptionMessage only needs to be protected for write.")]
  332. [SecuritySafeCritical]
  333. get { return helper.DeserializationExceptionMessage; }
  334. }
  335. internal bool IsReadOnlyContract
  336. {
  337. get { return this.DeserializationExceptionMessage != null; }
  338. }
  339. bool ItemNameSetExplicit
  340. {
  341. [Fx.Tag.SecurityNote(Critical = "Fetches the critical itemNameSetExplicit property.",
  342. Safe = "itemNameSetExplicit only needs to be protected for write.")]
  343. [SecuritySafeCritical]
  344. get { return helper.ItemNameSetExplicit; }
  345. }
  346. internal XmlFormatCollectionWriterDelegate XmlFormatWriterDelegate
  347. {
  348. [Fx.Tag.SecurityNote(Critical = "Fetches the critical xmlFormatWriterDelegate property.",
  349. Safe = "xmlFormatWriterDelegate only needs to be protected for write; initialized in getter if null.")]
  350. [SecuritySafeCritical]
  351. get
  352. {
  353. if (helper.XmlFormatWriterDelegate == null)
  354. {
  355. lock (this)
  356. {
  357. if (helper.XmlFormatWriterDelegate == null)
  358. {
  359. XmlFormatCollectionWriterDelegate tempDelegate = new XmlFormatWriterGenerator().GenerateCollectionWriter(this);
  360. Thread.MemoryBarrier();
  361. helper.XmlFormatWriterDelegate = tempDelegate;
  362. }
  363. }
  364. }
  365. return helper.XmlFormatWriterDelegate;
  366. }
  367. }
  368. internal XmlFormatCollectionReaderDelegate XmlFormatReaderDelegate
  369. {
  370. [Fx.Tag.SecurityNote(Critical = "Fetches the critical xmlFormatReaderDelegate property.",
  371. Safe = "xmlFormatReaderDelegate only needs to be protected for write; initialized in getter if null.")]
  372. [SecuritySafeCritical]
  373. get
  374. {
  375. if (helper.XmlFormatReaderDelegate == null)
  376. {
  377. lock (this)
  378. {
  379. if (helper.XmlFormatReaderDelegate == null)
  380. {
  381. if (this.IsReadOnlyContract)
  382. {
  383. ThrowInvalidDataContractException(helper.DeserializationExceptionMessage, null /*type*/);
  384. }
  385. XmlFormatCollectionReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateCollectionReader(this);
  386. Thread.MemoryBarrier();
  387. helper.XmlFormatReaderDelegate = tempDelegate;
  388. }
  389. }
  390. }
  391. return helper.XmlFormatReaderDelegate;
  392. }
  393. }
  394. internal XmlFormatGetOnlyCollectionReaderDelegate XmlFormatGetOnlyCollectionReaderDelegate
  395. {
  396. [Fx.Tag.SecurityNote(Critical = "Fetches the critical xmlFormatGetOnlyCollectionReaderDelegate property.",
  397. Safe = "xmlFormatGetOnlyCollectionReaderDelegate only needs to be protected for write; initialized in getter if null.")]
  398. [SecuritySafeCritical]
  399. get
  400. {
  401. if (helper.XmlFormatGetOnlyCollectionReaderDelegate == null)
  402. {
  403. lock (this)
  404. {
  405. if (helper.XmlFormatGetOnlyCollectionReaderDelegate == null)
  406. {
  407. if (this.UnderlyingType.IsInterface && (this.Kind == CollectionKind.Enumerable || this.Kind == CollectionKind.Collection || this.Kind == CollectionKind.GenericEnumerable))
  408. {
  409. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.GetOnlyCollectionMustHaveAddMethod, DataContract.GetClrTypeFullName(this.UnderlyingType))));
  410. }
  411. if (this.IsReadOnlyContract)
  412. {
  413. ThrowInvalidDataContractException(helper.DeserializationExceptionMessage, null /*type*/);
  414. }
  415. Fx.Assert(this.AddMethod != null || this.Kind == CollectionKind.Array, "Add method cannot be null if the collection is being used as a get-only property");
  416. XmlFormatGetOnlyCollectionReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateGetOnlyCollectionReader(this);
  417. Thread.MemoryBarrier();
  418. helper.XmlFormatGetOnlyCollectionReaderDelegate = tempDelegate;
  419. }
  420. }
  421. }
  422. return helper.XmlFormatGetOnlyCollectionReaderDelegate;
  423. }
  424. }
  425. [Fx.Tag.SecurityNote(Critical = "Holds all state used for (de)serializing collections. Since the data is cached statically, we lock down access to it.")]
  426. #if !NO_SECURITY_ATTRIBUTES
  427. [SecurityCritical(SecurityCriticalScope.Everything)]
  428. #endif
  429. class CollectionDataContractCriticalHelper : DataContract.DataContractCriticalHelper
  430. {
  431. static Type[] _knownInterfaces;
  432. Type itemType;
  433. bool isItemTypeNullable;
  434. CollectionKind kind;
  435. readonly MethodInfo getEnumeratorMethod, addMethod;
  436. readonly ConstructorInfo constructor;
  437. readonly string serializationExceptionMessage, deserializationExceptionMessage;
  438. DataContract itemContract;
  439. DataContract sharedTypeContract;
  440. DataContractDictionary knownDataContracts;
  441. bool isKnownTypeAttributeChecked;
  442. string itemName;
  443. bool itemNameSetExplicit;
  444. XmlDictionaryString collectionItemName;
  445. string keyName;
  446. string valueName;
  447. XmlDictionaryString childElementNamespace;
  448. string invalidCollectionInSharedContractMessage;
  449. XmlFormatCollectionReaderDelegate xmlFormatReaderDelegate;
  450. XmlFormatGetOnlyCollectionReaderDelegate xmlFormatGetOnlyCollectionReaderDelegate;
  451. XmlFormatCollectionWriterDelegate xmlFormatWriterDelegate;
  452. bool isConstructorCheckRequired = false;
  453. internal static Type[] KnownInterfaces
  454. {
  455. get
  456. {
  457. if (_knownInterfaces == null)
  458. {
  459. // Listed in priority order
  460. _knownInterfaces = new Type[]
  461. {
  462. Globals.TypeOfIDictionaryGeneric,
  463. Globals.TypeOfIDictionary,
  464. Globals.TypeOfIListGeneric,
  465. Globals.TypeOfICollectionGeneric,
  466. Globals.TypeOfIList,
  467. Globals.TypeOfIEnumerableGeneric,
  468. Globals.TypeOfICollection,
  469. Globals.TypeOfIEnumerable
  470. };
  471. }
  472. return _knownInterfaces;
  473. }
  474. }
  475. void Init(CollectionKind kind, Type itemType, CollectionDataContractAttribute collectionContractAttribute)
  476. {
  477. this.kind = kind;
  478. if (itemType != null)
  479. {
  480. this.itemType = itemType;
  481. this.isItemTypeNullable = DataContract.IsTypeNullable(itemType);
  482. bool isDictionary = (kind == CollectionKind.Dictionary || kind == CollectionKind.GenericDictionary);
  483. string itemName = null, keyName = null, valueName = null;
  484. if (collectionContractAttribute != null)
  485. {
  486. if (collectionContractAttribute.IsItemNameSetExplicitly)
  487. {
  488. if (collectionContractAttribute.ItemName == null || collectionContractAttribute.ItemName.Length == 0)
  489. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractItemName, DataContract.GetClrTypeFullName(UnderlyingType))));
  490. itemName = DataContract.EncodeLocalName(collectionContractAttribute.ItemName);
  491. itemNameSetExplicit = true;
  492. }
  493. if (collectionContractAttribute.IsKeyNameSetExplicitly)
  494. {
  495. if (collectionContractAttribute.KeyName == null || collectionContractAttribute.KeyName.Length == 0)
  496. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractKeyName, DataContract.GetClrTypeFullName(UnderlyingType))));
  497. if (!isDictionary)
  498. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractKeyNoDictionary, DataContract.GetClrTypeFullName(UnderlyingType), collectionContractAttribute.KeyName)));
  499. keyName = DataContract.EncodeLocalName(collectionContractAttribute.KeyName);
  500. }
  501. if (collectionContractAttribute.IsValueNameSetExplicitly)
  502. {
  503. if (collectionContractAttribute.ValueName == null || collectionContractAttribute.ValueName.Length == 0)
  504. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractValueName, DataContract.GetClrTypeFullName(UnderlyingType))));
  505. if (!isDictionary)
  506. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractValueNoDictionary, DataContract.GetClrTypeFullName(UnderlyingType), collectionContractAttribute.ValueName)));
  507. valueName = DataContract.EncodeLocalName(collectionContractAttribute.ValueName);
  508. }
  509. }
  510. XmlDictionary dictionary = isDictionary ? new XmlDictionary(5) : new XmlDictionary(3);
  511. this.Name = dictionary.Add(this.StableName.Name);
  512. this.Namespace = dictionary.Add(this.StableName.Namespace);
  513. this.itemName = itemName ?? DataContract.GetStableName(DataContract.UnwrapNullableType(itemType)).Name;
  514. this.collectionItemName = dictionary.Add(this.itemName);
  515. if (isDictionary)
  516. {
  517. this.keyName = keyName ?? Globals.KeyLocalName;
  518. this.valueName = valueName ?? Globals.ValueLocalName;
  519. }
  520. }
  521. if (collectionContractAttribute != null)
  522. {
  523. this.IsReference = collectionContractAttribute.IsReference;
  524. }
  525. }
  526. internal CollectionDataContractCriticalHelper(CollectionKind kind)
  527. : base()
  528. {
  529. Init(kind, null, null);
  530. }
  531. // array
  532. internal CollectionDataContractCriticalHelper(Type type)
  533. : base(type)
  534. {
  535. if (type == Globals.TypeOfArray)
  536. type = Globals.TypeOfObjectArray;
  537. if (type.GetArrayRank() > 1)
  538. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SupportForMultidimensionalArraysNotPresent)));
  539. this.StableName = DataContract.GetStableName(type);
  540. Init(CollectionKind.Array, type.GetElementType(), null);
  541. }
  542. // array
  543. internal CollectionDataContractCriticalHelper(Type type, DataContract itemContract)
  544. : base(type)
  545. {
  546. if (type.GetArrayRank() > 1)
  547. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SupportForMultidimensionalArraysNotPresent)));
  548. this.StableName = CreateQualifiedName(Globals.ArrayPrefix + itemContract.StableName.Name, itemContract.StableName.Namespace);
  549. this.itemContract = itemContract;
  550. Init(CollectionKind.Array, type.GetElementType(), null);
  551. }
  552. // read-only collection
  553. internal CollectionDataContractCriticalHelper(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, string serializationExceptionMessage, string deserializationExceptionMessage)
  554. : base(type)
  555. {
  556. if (getEnumeratorMethod == null)
  557. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.CollectionMustHaveGetEnumeratorMethod, DataContract.GetClrTypeFullName(type))));
  558. if (itemType == null)
  559. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.CollectionMustHaveItemType, DataContract.GetClrTypeFullName(type))));
  560. CollectionDataContractAttribute collectionContractAttribute;
  561. this.StableName = DataContract.GetCollectionStableName(type, itemType, out collectionContractAttribute);
  562. Init(kind, itemType, collectionContractAttribute);
  563. this.getEnumeratorMethod = getEnumeratorMethod;
  564. this.serializationExceptionMessage = serializationExceptionMessage;
  565. this.deserializationExceptionMessage = deserializationExceptionMessage;
  566. }
  567. // collection
  568. internal CollectionDataContractCriticalHelper(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor)
  569. : this(type, kind, itemType, getEnumeratorMethod, (string)null, (string)null)
  570. {
  571. if (addMethod == null && !type.IsInterface)
  572. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.CollectionMustHaveAddMethod, DataContract.GetClrTypeFullName(type))));
  573. this.addMethod = addMethod;
  574. this.constructor = constructor;
  575. }
  576. // collection
  577. internal CollectionDataContractCriticalHelper(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor, bool isConstructorCheckRequired)
  578. : this(type, kind, itemType, getEnumeratorMethod, addMethod, constructor)
  579. {
  580. this.isConstructorCheckRequired = isConstructorCheckRequired;
  581. }
  582. internal CollectionDataContractCriticalHelper(Type type, string invalidCollectionInSharedContractMessage)
  583. : base(type)
  584. {
  585. Init(CollectionKind.Collection, null /*itemType*/, null);
  586. this.invalidCollectionInSharedContractMessage = invalidCollectionInSharedContractMessage;
  587. }
  588. internal CollectionKind Kind
  589. {
  590. get { return kind; }
  591. }
  592. internal Type ItemType
  593. {
  594. get { return itemType; }
  595. }
  596. internal DataContract ItemContract
  597. {
  598. get
  599. {
  600. if (itemContract == null && UnderlyingType != null)
  601. {
  602. if (IsDictionary)
  603. {
  604. if (String.CompareOrdinal(KeyName, ValueName) == 0)
  605. {
  606. DataContract.ThrowInvalidDataContractException(
  607. SR.GetString(SR.DupKeyValueName, DataContract.GetClrTypeFullName(UnderlyingType), KeyName),
  608. UnderlyingType);
  609. }
  610. itemContract = ClassDataContract.CreateClassDataContractForKeyValue(ItemType, Namespace, new string[] { KeyName, ValueName });
  611. // Ensure that DataContract gets added to the static DataContract cache for dictionary items
  612. DataContract.GetDataContract(ItemType);
  613. }
  614. else
  615. {
  616. itemContract = DataContract.GetDataContract(ItemType);
  617. }
  618. }
  619. return itemContract;
  620. }
  621. set
  622. {
  623. itemContract = value;
  624. }
  625. }
  626. internal DataContract SharedTypeContract
  627. {
  628. get { return sharedTypeContract; }
  629. set { sharedTypeContract = value; }
  630. }
  631. internal string ItemName
  632. {
  633. get { return itemName; }
  634. set { itemName = value; }
  635. }
  636. internal bool IsConstructorCheckRequired
  637. {
  638. get { return isConstructorCheckRequired; }
  639. set { isConstructorCheckRequired = value; }
  640. }
  641. public XmlDictionaryString CollectionItemName
  642. {
  643. get { return collectionItemName; }
  644. }
  645. internal string KeyName
  646. {
  647. get { return keyName; }
  648. set { keyName = value; }
  649. }
  650. internal string ValueName
  651. {
  652. get { return valueName; }
  653. set { valueName = value; }
  654. }
  655. internal bool IsDictionary
  656. {
  657. get { return KeyName != null; }
  658. }
  659. public string SerializationExceptionMessage
  660. {
  661. get { return serializationExceptionMessage; }
  662. }
  663. public string DeserializationExceptionMessage
  664. {
  665. get { return deserializationExceptionMessage; }
  666. }
  667. public XmlDictionaryString ChildElementNamespace
  668. {
  669. get { return childElementNamespace; }
  670. set { childElementNamespace = value; }
  671. }
  672. internal bool IsItemTypeNullable
  673. {
  674. get { return isItemTypeNullable; }
  675. set { isItemTypeNullable = value; }
  676. }
  677. internal MethodInfo GetEnumeratorMethod
  678. {
  679. get { return getEnumeratorMethod; }
  680. }
  681. internal MethodInfo AddMethod
  682. {
  683. get { return addMethod; }
  684. }
  685. internal ConstructorInfo Constructor
  686. {
  687. get { return constructor; }
  688. }
  689. internal override DataContractDictionary KnownDataContracts
  690. {
  691. get
  692. {
  693. if (!isKnownTypeAttributeChecked && UnderlyingType != null)
  694. {
  695. lock (this)
  696. {
  697. if (!isKnownTypeAttributeChecked)
  698. {
  699. knownDataContracts = DataContract.ImportKnownTypeAttributes(this.UnderlyingType);
  700. Thread.MemoryBarrier();
  701. isKnownTypeAttributeChecked = true;
  702. }
  703. }
  704. }
  705. return knownDataContracts;
  706. }
  707. set { knownDataContracts = value; }
  708. }
  709. internal string InvalidCollectionInSharedContractMessage
  710. {
  711. get { return invalidCollectionInSharedContractMessage; }
  712. }
  713. internal bool ItemNameSetExplicit
  714. {
  715. get { return itemNameSetExplicit; }
  716. }
  717. internal XmlFormatCollectionWriterDelegate XmlFormatWriterDelegate
  718. {
  719. get { return xmlFormatWriterDelegate; }
  720. set { xmlFormatWriterDelegate = value; }
  721. }
  722. internal XmlFormatCollectionReaderDelegate XmlFormatReaderDelegate
  723. {
  724. get { return xmlFormatReaderDelegate; }
  725. set { xmlFormatReaderDelegate = value; }
  726. }
  727. internal XmlFormatGetOnlyCollectionReaderDelegate XmlFormatGetOnlyCollectionReaderDelegate
  728. {
  729. get { return xmlFormatGetOnlyCollectionReaderDelegate; }
  730. set { xmlFormatGetOnlyCollectionReaderDelegate = value; }
  731. }
  732. }
  733. DataContract GetSharedTypeContract(Type type)
  734. {
  735. if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false))
  736. {
  737. return this;
  738. }
  739. // ClassDataContract.IsNonAttributedTypeValidForSerialization does not need to be called here. It should
  740. // never pass because it returns false for types that implement any of CollectionDataContract.KnownInterfaces
  741. if (type.IsSerializable || type.IsDefined(Globals.TypeOfDataContractAttribute, false))
  742. {
  743. return new ClassDataContract(type);
  744. }
  745. return null;
  746. }
  747. internal static bool IsCollectionInterface(Type type)
  748. {
  749. if (type.IsGenericType)
  750. type = type.GetGenericTypeDefinition();
  751. return ((IList<Type>)KnownInterfaces).Contains(type);
  752. }
  753. internal static bool IsCollection(Type type)
  754. {
  755. Type itemType;
  756. return IsCollection(type, out itemType);
  757. }
  758. internal static bool IsCollection(Type type, out Type itemType)
  759. {
  760. return IsCollectionHelper(type, out itemType, true /*constructorRequired*/);
  761. }
  762. internal static bool IsCollection(Type type, bool constructorRequired, bool skipIfReadOnlyContract)
  763. {
  764. Type itemType;
  765. return IsCollectionHelper(type, out itemType, constructorRequired, skipIfReadOnlyContract);
  766. }
  767. static bool IsCollectionHelper(Type type, out Type itemType, bool constructorRequired, bool skipIfReadOnlyContract = false)
  768. {
  769. if (type.IsArray && DataContract.GetBuiltInDataContract(type) == null)
  770. {
  771. itemType = type.GetElementType();
  772. return true;
  773. }
  774. DataContract dataContract;
  775. return IsCollectionOrTryCreate(type, false /*tryCreate*/, out dataContract, out itemType, constructorRequired, skipIfReadOnlyContract);
  776. }
  777. internal static bool TryCreate(Type type, out DataContract dataContract)
  778. {
  779. Type itemType;
  780. return IsCollectionOrTryCreate(type, true /*tryCreate*/, out dataContract, out itemType, true /*constructorRequired*/);
  781. }
  782. internal static bool TryCreateGetOnlyCollectionDataContract(Type type, out DataContract dataContract)
  783. {
  784. Type itemType;
  785. if (type.IsArray)
  786. {
  787. dataContract = new CollectionDataContract(type);
  788. return true;
  789. }
  790. else
  791. {
  792. return IsCollectionOrTryCreate(type, true /*tryCreate*/, out dataContract, out itemType, false /*constructorRequired*/);
  793. }
  794. }
  795. internal static MethodInfo GetTargetMethodWithName(string name, Type type, Type interfaceType)
  796. {
  797. InterfaceMapping mapping = type.GetInterfaceMap(interfaceType);
  798. for (int i = 0; i < mapping.TargetMethods.Length; i++)
  799. {
  800. if (mapping.InterfaceMethods[i].Name == name)
  801. return mapping.InterfaceMethods[i];
  802. }
  803. return null;
  804. }
  805. static bool IsArraySegment(Type t)
  806. {
  807. return t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(ArraySegment<>));
  808. }
  809. [System.Diagnostics.CodeAnalysis.SuppressMessage(FxCop.Category.Globalization, FxCop.Rule.DoNotPassLiteralsAsLocalizedParameters, Justification = "Private code.")]
  810. static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataContract dataContract, out Type itemType, bool constructorRequired, bool skipIfReadOnlyContract = false)
  811. {
  812. dataContract = null;
  813. itemType = Globals.TypeOfObject;
  814. if (DataContract.GetBuiltInDataContract(type) != null)
  815. {
  816. return HandleIfInvalidCollection(type, tryCreate, false/*hasCollectionDataContract*/, false/*isBaseTypeCollection*/,
  817. SR.CollectionTypeCannotBeBuiltIn, null, ref dataContract);
  818. }
  819. MethodInfo addMethod, getEnumeratorMethod;
  820. bool hasCollectionDataContract = IsCollectionDataContract(type);
  821. bool isReadOnlyContract = false;
  822. string serializationExceptionMessage = null, deserializationExceptionMessage = null;
  823. Type baseType = type.BaseType;
  824. bool isBaseTypeCollection = (baseType != null && baseType != Globals.TypeOfObject
  825. && baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri) ? IsCollection(baseType) : false;
  826. // Avoid creating an invalid collection contract for Serializable types since we can create a ClassDataContract instead
  827. bool createContractWithException = isBaseTypeCollection && !type.IsSerializable;
  828. if (type.IsDefined(Globals.TypeOfDataContractAttribute, false))
  829. {
  830. return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException,
  831. SR.CollectionTypeCannotHaveDataContract, null, ref dataContract);
  832. }
  833. if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type) || IsArraySegment(type))
  834. {
  835. return false;
  836. }
  837. if (!Globals.TypeOfIEnumerable.IsAssignableFrom(type))
  838. {
  839. return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException,
  840. SR.CollectionTypeIsNotIEnumerable, null, ref dataContract);
  841. }
  842. if (type.IsInterface)
  843. {
  844. Type interfaceTypeToCheck = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
  845. Type[] knownInterfaces = KnownInterfaces;
  846. for (int i = 0; i < knownInterfaces.Length; i++)
  847. {
  848. if (knownInterfaces[i] == interfaceTypeToCheck)
  849. {
  850. addMethod = null;
  851. if (type.IsGenericType)
  852. {
  853. Type[] genericArgs = type.GetGenericArguments();
  854. if (interfaceTypeToCheck == Globals.TypeOfIDictionaryGeneric)
  855. {
  856. itemType = Globals.TypeOfKeyValue.MakeGenericType(genericArgs);
  857. addMethod = type.GetMethod(Globals.AddMethodName);
  858. getEnumeratorMethod = Globals.TypeOfIEnumerableGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(genericArgs)).GetMethod(Globals.GetEnumeratorMethodName);
  859. }
  860. else
  861. {
  862. itemType = genericArgs[0];
  863. if (interfaceTypeToCheck == Globals.TypeOfICollectionGeneric || interfaceTypeToCheck == Globals.TypeOfIListGeneric)
  864. {
  865. addMethod = Globals.TypeOfICollectionGeneric.MakeGenericType(itemType).GetMethod(Globals.AddMethodName);
  866. }
  867. getEnumeratorMethod = Globals.TypeOfIEnumerableGeneric.MakeGenericType(itemType).GetMethod(Globals.GetEnumeratorMethodName);
  868. }
  869. }
  870. else
  871. {
  872. if (interfaceTypeToCheck == Globals.TypeOfIDictionary)
  873. {
  874. itemType = typeof(KeyValue<object, object>);
  875. addMethod = type.GetMethod(Globals.AddMethodName);
  876. }
  877. else
  878. {
  879. itemType = Globals.TypeOfObject;
  880. if (interfaceTypeToCheck == Globals.TypeOfIList)
  881. {
  882. addMethod = Globals.TypeOfIList.GetMethod(Globals.AddMethodName);
  883. }
  884. }
  885. getEnumeratorMethod = Globals.TypeOfIEnumerable.GetMethod(Globals.GetEnumeratorMethodName);
  886. }
  887. if (tryCreate)
  888. dataContract = new CollectionDataContract(type, (CollectionKind)(i + 1), itemType, getEnumeratorMethod, addMethod, null/*defaultCtor*/);
  889. return true;
  890. }
  891. }
  892. }
  893. ConstructorInfo defaultCtor = null;
  894. if (!type.IsValueType)
  895. {
  896. defaultCtor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Globals.EmptyTypeArray, null);
  897. if (defaultCtor == null && constructorRequired)
  898. {
  899. // All collection types could be considered read-only collections except collection types that are marked [Serializable].
  900. // Collection types marked [Serializable] cannot be read-only collections for backward compatibility reasons.
  901. // DataContract types and POCO types cannot be collection types, so they don't need to be factored in
  902. if (type.IsSerializable)
  903. {
  904. return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException,
  905. SR.CollectionTypeDoesNotHaveDefaultCtor, null, ref dataContract);
  906. }
  907. else
  908. {
  909. isReadOnlyContract = true;
  910. GetReadOnlyCollectionExceptionMessages(type, hasCollectionDataContract, SR.CollectionTypeDoesNotHaveDefaultCtor, null, out serializationExceptionMessage, out deserializationExceptionMessage);
  911. }
  912. }
  913. }
  914. Type knownInterfaceType = null;
  915. CollectionKind kind = CollectionKind.None;
  916. bool multipleDefinitions = false;
  917. Type[] interfaceTypes = type.GetInterfaces();
  918. foreach (Type interfaceType in interfaceTypes)
  919. {
  920. Type interfaceTypeToCheck = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType;
  921. Type[] knownInterfaces = KnownInterfaces;
  922. for (int i = 0; i < knownInterfaces.Length; i++)
  923. {
  924. if (knownInterfaces[i] == interfaceTypeToCheck)
  925. {
  926. CollectionKind currentKind = (CollectionKind)(i + 1);
  927. if (kind == CollectionKind.None || currentKind < kind)
  928. {
  929. kind = currentKind;
  930. knownInterfaceType = interfaceType;
  931. multipleDefinitions = false;
  932. }
  933. else if ((kind & currentKind) == currentKind)
  934. multipleDefinitions = true;
  935. break;
  936. }
  937. }
  938. }
  939. if (kind == CollectionKind.None)
  940. {
  941. return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException,
  942. SR.CollectionTypeIsNotIEnumerable, null, ref dataContract);
  943. }
  944. if (kind == CollectionKind.Enumerable || kind == CollectionKind.Collection || kind == CollectionKind.GenericEnumerable)
  945. {
  946. if (multipleDefinitions)
  947. knownInterfaceType = Globals.TypeOfIEnumerable;
  948. itemType = knownInterfaceType.IsGenericType ? knownInterfaceType.GetGenericArguments()[0] : Globals.TypeOfObject;
  949. GetCollectionMethods(type, knownInterfaceType, new Type[] { itemType },
  950. false /*addMethodOnInterface*/,
  951. out getEnumeratorMethod, out addMethod);
  952. if (addMethod == null)
  953. {
  954. // All collection types could be considered read-only collections except collection types that are marked [Serializable].
  955. // Collection types marked [Serializable] cannot be read-only collections for backward compatibility reasons.
  956. // DataContract types and POCO types cannot be collection types, so they don't need to be factored in.
  957. if (type.IsSerializable || skipIfReadOnlyContract)
  958. {
  959. return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException && !skipIfReadOnlyContract,
  960. SR.CollectionTypeDoesNotHaveAddMethod, DataContract.GetClrTypeFullName(itemType), ref dataContract);
  961. }
  962. else
  963. {
  964. isReadOnlyContract = true;
  965. GetReadOnlyCollectionExceptionMessages(type, hasCollectionDataContract, SR.CollectionTypeDoesNotHaveAddMethod, DataContract.GetClrTypeFullName(itemType), out serializationExceptionMessage, out deserializationExceptionMessage);
  966. }
  967. }
  968. if (tryCreate)
  969. {
  970. dataContract = isReadOnlyContract ?
  971. new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage) :
  972. new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, addMethod, defaultCtor, !constructorRequired);
  973. }
  974. }
  975. else
  976. {
  977. if (multipleDefinitions)
  978. {
  979. return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException,
  980. SR.CollectionTypeHasMultipleDefinitionsOfInterface, KnownInterfaces[(int)kind - 1].Name, ref dataContract);
  981. }
  982. Type[] addMethodTypeArray = null;
  983. switch (kind)
  984. {
  985. case CollectionKind.GenericDictionary:
  986. addMethodTypeArray = knownInterfaceType.GetGenericArguments();
  987. bool isOpenGeneric = knownInterfaceType.IsGenericTypeDefinition
  988. || (addMethodTypeArray[0].IsGenericParameter && addMethodTypeArray[1].IsGenericParameter);
  989. itemType = isOpenGeneric ? Globals.TypeOfKeyValue : Globals.TypeOfKeyValue.MakeGenericType(addMethodTypeArray);
  990. break;
  991. case CollectionKind.Dictionary:
  992. addMethodTypeArray = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
  993. itemType = Globals.TypeOfKeyValue.MakeGenericType(addMethodTypeArray);
  994. break;
  995. case CollectionKind.GenericList:
  996. case CollectionKind.GenericCollection:
  997. addMethodTypeArray = knownInterfaceType.GetGenericArguments();
  998. itemType = addMethodTypeArray[0];
  999. break;
  1000. case CollectionKind.List:
  1001. itemType = Globals.TypeOfObject;
  1002. addMethodTypeArray = new Type[] { itemType };
  1003. break;
  1004. }
  1005. if (tryCreate)
  1006. {
  1007. GetCollectionMethods(type, knownInterfaceType, addMethodTypeArray,
  1008. true /*addMethodOnInterface*/,
  1009. out getEnumeratorMethod, out addMethod);
  1010. dataContract = isReadOnlyContract ?
  1011. new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage) :
  1012. new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, addMethod, defaultCtor, !constructorRequired);
  1013. }
  1014. }
  1015. return !(isReadOnlyContract && skipIfReadOnlyContract);
  1016. }
  1017. internal static bool IsCollectionDataContract(Type type)
  1018. {
  1019. return type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false);
  1020. }
  1021. static bool HandleIfInvalidCollection(Type type, bool tryCreate, bool hasCollectionDataContract, bool createContractWithException, string message, string param, ref DataContract dataContract)
  1022. {
  1023. if (hasCollectionDataContract)
  1024. {
  1025. if (tryCreate)
  1026. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(GetInvalidCollectionMessage(message, SR.GetString(SR.InvalidCollectionDataContract, DataContract.GetClrTypeFullName(type)), param)));
  1027. return true;
  1028. }
  1029. if (createContractWithException)
  1030. {
  1031. if (tryCreate)
  1032. dataContract = new CollectionDataContract(type, GetInvalidCollectionMessage(message, SR.GetString(SR.InvalidCollectionType, DataContract.GetClrTypeFullName(type)), param));
  1033. return true;
  1034. }
  1035. return false;
  1036. }
  1037. static void GetReadOnlyCollectionExceptionMessages(Type type, bool hasCollectionDataContract, string message, string param, out string serializationExceptionMessage, out string deserializationExceptionMessage)
  1038. {
  1039. serializationExceptionMessage = GetInvalidCollectionMessage(message, SR.GetString(hasCollectionDataContract ? SR.InvalidCollectionDataContract : SR.InvalidCollectionType, DataContract.GetClrTypeFullName(type)), param);
  1040. deserializationExceptionMessage = GetInvalidCollectionMessage(message, SR.GetString(SR.ReadOnlyCollectionDeserialization, DataContract.GetClrTypeFullName(type)), param);
  1041. }
  1042. static string GetInvalidCollectionMessage(string message, string nestedMessage, string param)
  1043. {
  1044. return (param == null) ? SR.GetString(message, nestedMessage) : SR.GetString(message, nestedMessage, param);
  1045. }
  1046. static void FindCollectionMethodsOnInterface(Type type, Type interfaceType, ref MethodInfo addMethod, ref MethodInfo getEnumeratorMethod)
  1047. {
  1048. InterfaceMapping mapping = type.GetInterfaceMap(interfaceType);
  1049. for (int i = 0; i < mapping.TargetMethods.Length; i++)
  1050. {
  1051. if (mapping.InterfaceMethods[i].Name == Globals.AddMethodName)
  1052. addMethod = mapping.InterfaceMethods[i];
  1053. else if (mapping.InterfaceMethods[i].Name == Globals.GetEnumeratorMethodName)
  1054. getEnumeratorMethod = mapping.InterfaceMethods[i];
  1055. }
  1056. }
  1057. static void GetCollectionMethods(Type type, Type interfaceType, Type[] addMethodTypeArray, bool addMethodOnInterface, out MethodInfo getEnumeratorMethod, out MethodInfo addMethod)
  1058. {
  1059. addMethod = getEnumeratorMethod = null;
  1060. if (addMethodOnInterface)
  1061. {
  1062. addMethod = type.GetMethod(Globals.AddMethodName, BindingFlags.Instance | BindingFlags.Public, null, addMethodTypeArray, null);
  1063. if (addMethod == null || addMethod.GetParameters()[0].ParameterType != addMethodTypeArray[0])
  1064. {
  1065. FindCollectionMethodsOnInterface(type, interfaceType, ref addMethod, ref getEnumeratorMethod);
  1066. if (addMethod == null)
  1067. {
  1068. Type[] parentInterfaceTypes = interfaceType.GetInterfaces();
  1069. foreach (Type parentInterfaceType in parentInterfaceTypes)
  1070. {
  1071. if (IsKnownInterface(parentInterfaceType))
  1072. {
  1073. FindCollectionMethodsOnInterface(type, parentInterfaceType, ref addMethod, ref getEnumeratorMethod);
  1074. if (addMethod == null)
  1075. {
  1076. break;
  1077. }
  1078. }
  1079. }
  1080. }
  1081. }
  1082. }
  1083. else
  1084. {
  1085. // GetMethod returns Add() method with parameter closest matching T in assignability/inheritance chain
  1086. addMethod = type.GetMethod(Globals.AddMethodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, addMethodTypeArray, null);
  1087. }
  1088. if (getEnumeratorMethod == null)
  1089. {
  1090. getEnumeratorMethod = type.GetMethod(Globals.GetEnumeratorMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
  1091. if (getEnumeratorMethod == null || !Globals.TypeOfIEnumerator.IsAssignableFrom(getEnumeratorMethod.ReturnType))
  1092. {
  1093. Type ienumerableInterface = interfaceType.GetInterface("System.Collections.Generic.IEnumerable*");
  1094. if (ienumerableInterface == null)
  1095. ienumerableInterface = Globals.TypeOfIEnumerable;
  1096. getEnumeratorMethod = GetTargetMethodWithName(Globals.GetEnumeratorMethodName, type, ienumerableInterface);
  1097. }
  1098. }
  1099. }
  1100. static bool IsKnownInterface(Type type)
  1101. {
  1102. Type typeToCheck = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
  1103. foreach (Type knownInterfaceType in KnownInterfaces)
  1104. {
  1105. if (typeToCheck == knownInterfaceType)
  1106. {
  1107. return true;
  1108. }
  1109. }
  1110. return false;
  1111. }
  1112. [Fx.Tag.SecurityNote(Critical = "Sets critical properties on CollectionDataContract .",
  1113. Safe = "Called during schema import/code generation.")]
  1114. [SecuritySafeCritical]
  1115. internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary<DataContract, DataContract> boundContracts)
  1116. {
  1117. DataContract boundContract;
  1118. if (boundContracts.TryGetValue(this, out boundContract))
  1119. return boundContract;
  1120. CollectionDataContract boundCollectionContract = new CollectionDataContract(Kind);
  1121. boundContracts.Add(this, boundCollectionContract);
  1122. boundCollectionContract.ItemContract = this.ItemContract.BindGenericParameters(paramContracts, boundContracts);
  1123. boundCollectionContract.IsItemTypeNullable = !boundCollectionContract.ItemContract.IsValueType;
  1124. boundCollectionContract.ItemName = ItemNameSetExplicit ? this.ItemName : boundCollectionContract.ItemContract.StableName.Name;
  1125. boundCollectionContract.KeyName = this.KeyName;
  1126. boundCollectionContract.ValueName = this.ValueName;
  1127. boundCollectionContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(this.StableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(this.UnderlyingType), paramContracts)),
  1128. IsCollectionDataContract(UnderlyingType) ? this.StableName.Namespace : DataContract.GetCollectionNamespace(boundCollectionContract.ItemContract.StableName.Namespace));
  1129. return boundCollectionContract;
  1130. }
  1131. internal override DataContract GetValidContract(SerializationMode mode)
  1132. {
  1133. if (mode == SerializationMode.SharedType)
  1134. {
  1135. if (SharedTypeContract == null)
  1136. DataContract.ThrowTypeNotSerializable(UnderlyingType);
  1137. return SharedTypeContract;
  1138. }
  1139. ThrowIfInvalid();
  1140. return this;
  1141. }
  1142. void ThrowIfInvalid()
  1143. {
  1144. if (InvalidCollectionInSharedContractMessage != null)
  1145. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(InvalidCollectionInSharedContractMessage));
  1146. }
  1147. internal override DataContract GetValidContract()
  1148. {
  1149. if (this.IsConstructorCheckRequired)
  1150. {
  1151. CheckConstructor();
  1152. }
  1153. return this;
  1154. }
  1155. [Fx.Tag.SecurityNote(Critical = "Sets the critical IsConstructorCheckRequired property on CollectionDataContract.",
  1156. Safe = "Does not leak anything.")]
  1157. [SecuritySafeCritical]
  1158. void CheckConstructor()
  1159. {
  1160. if (this.Constructor == null)
  1161. {
  1162. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.CollectionTypeDoesNotHaveDefaultCtor, DataContract.GetClrTypeFullName(this.UnderlyingType))));
  1163. }
  1164. else
  1165. {
  1166. this.IsConstructorCheckRequired = false;
  1167. }
  1168. }
  1169. internal override bool IsValidContract(SerializationMode mode)
  1170. {
  1171. if (mode == SerializationMode.SharedType)
  1172. return (SharedTypeContract != null);
  1173. return (InvalidCollectionInSharedContractMessage == null);
  1174. }
  1175. #if !NO_DYNAMIC_CODEGEN
  1176. [Fx.Tag.SecurityNote(Miscellaneous =
  1177. "RequiresReview - Calculates whether this collection requires MemberAccessPermission for deserialization."
  1178. + " Since this information is used to determine whether to give the generated code access"
  1179. + " permissions to private members, any changes to the logic should be reviewed.")]
  1180. internal bool RequiresMemberAccessForRead(SecurityException securityException)
  1181. {
  1182. if (!IsTypeVisible(UnderlyingType))
  1183. {
  1184. if (securityException != null)
  1185. {
  1186. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1187. new SecurityException(SR.GetString(
  1188. SR.PartialTrustCollectionContractTypeNotPublic,
  1189. DataContract.GetClrTypeFullName(UnderlyingType)),
  1190. securityException));
  1191. }
  1192. return true;
  1193. }
  1194. if (ItemType != null && !IsTypeVisible(ItemType))
  1195. {
  1196. if (securityException != null)
  1197. {
  1198. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1199. new SecurityException(SR.GetString(
  1200. SR.PartialTrustCollectionContractTypeNotPublic,
  1201. DataContract.GetClrTypeFullName(ItemType)),
  1202. securityException));
  1203. }
  1204. return true;
  1205. }
  1206. if (ConstructorRequiresMemberAccess(Constructor))
  1207. {
  1208. if (securityException != null)
  1209. {
  1210. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1211. new SecurityException(SR.GetString(
  1212. SR.PartialTrustCollectionContractNoPublicConstructor,
  1213. DataContract.GetClrTypeFullName(UnderlyingType)),
  1214. securityException));
  1215. }
  1216. return true;
  1217. }
  1218. if (MethodRequiresMemberAccess(this.AddMethod))
  1219. {
  1220. if (securityException != null)
  1221. {
  1222. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1223. new SecurityException(SR.GetString(
  1224. SR.PartialTrustCollectionContractAddMethodNotPublic,
  1225. DataContract.GetClrTypeFullName(UnderlyingType),
  1226. this.AddMethod.Name),
  1227. securityException));
  1228. }
  1229. return true;
  1230. }
  1231. return false;
  1232. }
  1233. [Fx.Tag.SecurityNote(Miscellaneous =
  1234. "RequiresReview - Calculates whether this collection requires MemberAccessPermission for serialization."
  1235. + " Since this information is used to determine whether to give the generated code access"
  1236. + " permissions to private members, any changes to the logic should be reviewed.")]
  1237. internal bool RequiresMemberAccessForWrite(SecurityException securityException)
  1238. {
  1239. if (!IsTypeVisible(UnderlyingType))
  1240. {
  1241. if (securityException != null)
  1242. {
  1243. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1244. new SecurityException(SR.GetString(
  1245. SR.PartialTrustCollectionContractTypeNotPublic,
  1246. DataContract.GetClrTypeFullName(UnderlyingType)),
  1247. securityException));
  1248. }
  1249. return true;
  1250. }
  1251. if (ItemType != null && !IsTypeVisible(ItemType))
  1252. {
  1253. if (securityException != null)
  1254. {
  1255. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
  1256. new SecurityException(SR.GetString(
  1257. SR.PartialTrustCollectionContractTypeNotPublic,
  1258. DataContract.GetClrTypeFullName(ItemType)),
  1259. securityException));
  1260. }
  1261. return true;
  1262. }
  1263. return false;
  1264. }
  1265. #endif
  1266. internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
  1267. {
  1268. if (IsEqualOrChecked(other, checkedContracts))
  1269. return true;
  1270. if (base.Equals(other, checkedContracts))
  1271. {
  1272. CollectionDataContract dataContract = other as CollectionDataContract;
  1273. if (dataContract != null)
  1274. {
  1275. bool thisItemTypeIsNullable = (ItemContract == null) ? false : !ItemContract.IsValueType;
  1276. bool otherItemTypeIsNullable = (dataContract.ItemContract == null) ? false : !dataContract.ItemContract.IsValueType;
  1277. return ItemName == dataContract.ItemName &&
  1278. (IsItemTypeNullable || thisItemTypeIsNullable) == (dataContract.IsItemTypeNullable || otherItemTypeIsNullable) &&
  1279. ItemContract.Equals(dataContract.ItemContract, checkedContracts);
  1280. }
  1281. }
  1282. return false;
  1283. }
  1284. public override int GetHashCode()
  1285. {
  1286. return base.GetHashCode();
  1287. }
  1288. public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context)
  1289. {
  1290. // IsGetOnlyCollection value has already been used to create current collectiondatacontract, value can now be reset.
  1291. context.IsGetOnlyCollection = false;
  1292. XmlFormatWriterDelegate(xmlWriter, obj, context, this);
  1293. }
  1294. public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
  1295. {
  1296. xmlReader.Read();
  1297. object o = null;
  1298. if (context.IsGetOnlyCollection)
  1299. {
  1300. // IsGetOnlyCollection value has already been used to create current collectiondatacontract, value can now be reset.
  1301. context.IsGetOnlyCollection = false;
  1302. XmlFormatGetOnlyCollectionReaderDelegate(xmlReader, context, CollectionItemName, Namespace, this);
  1303. }
  1304. else
  1305. {
  1306. o = XmlFormatReaderDelegate(xmlReader, context, CollectionItemName, Namespace, this);
  1307. }
  1308. xmlReader.ReadEndElement();
  1309. return o;
  1310. }
  1311. public class DictionaryEnumerator : IEnumerator<KeyValue<object, object>>
  1312. {
  1313. IDictionaryEnumerator enumerator;
  1314. public DictionaryEnumerator(IDictionaryEnumerator enumerator)
  1315. {
  1316. this.enumerator = enumerator;
  1317. }
  1318. public void Dispose()
  1319. {
  1320. }
  1321. public bool MoveNext()
  1322. {
  1323. return enumerator.MoveNext();
  1324. }
  1325. public KeyValue<object, object> Current
  1326. {
  1327. get { return new KeyValue<object, object>(enumerator.Key, enumerator.Value); }
  1328. }
  1329. object System.Collections.IEnumerator.Current
  1330. {
  1331. get { return Current; }
  1332. }
  1333. public void Reset()
  1334. {
  1335. enumerator.Reset();
  1336. }
  1337. }
  1338. public class GenericDictionaryEnumerator<K, V> : IEnumerator<KeyValue<K, V>>
  1339. {
  1340. IEnumerator<KeyValuePair<K, V>> enumerator;
  1341. public GenericDictionaryEnumerator(IEnumerator<KeyValuePair<K, V>> enumerator)
  1342. {
  1343. this.enumerator = enumerator;
  1344. }
  1345. public void Dispose()
  1346. {
  1347. }
  1348. public bool MoveNext()
  1349. {
  1350. return enumerator.MoveNext();
  1351. }
  1352. public KeyValue<K, V> Current
  1353. {
  1354. get
  1355. {
  1356. KeyValuePair<K, V> current = enumerator.Current;
  1357. return new KeyValue<K, V>(current.Key, current.Value);
  1358. }
  1359. }
  1360. object System.Collections.IEnumerator.Current
  1361. {
  1362. get { return Current; }
  1363. }
  1364. public void Reset()
  1365. {
  1366. enumerator.Reset();
  1367. }
  1368. }
  1369. }
  1370. }