ef6fae6b46b9e3630d1a89e20c7a827748b6afe9
[mono.git] / mcs / class / referencesource / System.Runtime.Serialization / System / Runtime / Serialization / ClassDataContract.cs
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.Collections.Generic;
9     using System.Reflection;
10     using System.Security;
11     using System.Threading;
12     using System.Xml;
13     using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
14
15 #if USE_REFEMIT
16     public sealed class ClassDataContract : DataContract
17 #else
18     internal sealed class ClassDataContract : DataContract
19 #endif
20     {
21         [Fx.Tag.SecurityNote(Miscellaneous =
22             "RequiresReview - XmlDictionaryString(s) representing the XML namespaces for class members."
23             + "statically cached and used from IL generated code. should ideally be Critical."
24             + "marked SecurityNode to be callable from transparent IL generated code."
25             + "not changed to property to avoid regressing performance; any changes to initalization should be reviewed.")]
26         public XmlDictionaryString[] ContractNamespaces;
27
28         [Fx.Tag.SecurityNote(Miscellaneous =
29             "RequiresReview - XmlDictionaryString(s) representing the XML element names for class members."
30             + "statically cached and used from IL generated code. should ideally be Critical."
31             + "marked SecurityNode to be callable from transparent IL generated code."
32             + "not changed to property to avoid regressing performance; any changes to initalization should be reviewed.")]
33         public XmlDictionaryString[] MemberNames;
34
35         [Fx.Tag.SecurityNote(Miscellaneous =
36             "RequiresReview - XmlDictionaryString(s) representing the XML namespaces for class members."
37             + "statically cached and used from IL generated code. should ideally be Critical."
38             + "marked SecurityNode to be callable from transparent IL generated code."
39             + "not changed to property to avoid regressing performance; any changes to initalization should be reviewed.")]
40         public XmlDictionaryString[] MemberNamespaces;
41
42         [Fx.Tag.SecurityNote(Critical = "XmlDictionaryString representing the XML namespaces for members of class."
43             + "Statically cached and used from IL generated code.")]
44         [SecurityCritical]
45         XmlDictionaryString[] childElementNamespaces;
46
47         [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that is cached statically for serialization. "
48             + "Static fields are marked SecurityCritical or readonly to prevent data from being modified or leaked to other components in appdomain.")]
49         [SecurityCritical]
50         ClassDataContractCriticalHelper helper;
51
52         [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'",
53             Safe = "Doesn't leak anything.")]
54         [SecuritySafeCritical]
55         internal ClassDataContract()
56             : base(new ClassDataContractCriticalHelper())
57         {
58             InitClassDataContract();
59         }
60
61         [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'",
62             Safe = "Doesn't leak anything.")]
63         [SecuritySafeCritical]
64         internal ClassDataContract(Type type)
65             : base(new ClassDataContractCriticalHelper(type))
66         {
67             InitClassDataContract();
68         }
69
70         [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'",
71             Safe = "Doesn't leak anything.")]
72         [SecuritySafeCritical]
73         ClassDataContract(Type type, XmlDictionaryString ns, string[] memberNames)
74             : base(new ClassDataContractCriticalHelper(type, ns, memberNames))
75         {
76             InitClassDataContract();
77         }
78
79         [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical fields; called from all constructors.")]
80         [SecurityCritical]
81         void InitClassDataContract()
82         {
83             this.helper = base.Helper as ClassDataContractCriticalHelper;
84             this.ContractNamespaces = helper.ContractNamespaces;
85             this.MemberNames = helper.MemberNames;
86             this.MemberNamespaces = helper.MemberNamespaces;
87         }
88
89         internal ClassDataContract BaseContract
90         {
91             [Fx.Tag.SecurityNote(Critical = "Fetches the critical baseContract property.",
92                 Safe = "baseContract only needs to be protected for write.")]
93             [SecuritySafeCritical]
94             get { return helper.BaseContract; }
95
96             [Fx.Tag.SecurityNote(Critical = "Sets the critical baseContract property.")]
97             [SecurityCritical]
98             set { helper.BaseContract = value; }
99         }
100
101         internal List<DataMember> Members
102         {
103             [Fx.Tag.SecurityNote(Critical = "Fetches the critical members property.",
104                 Safe = "members only needs to be protected for write.")]
105             [SecuritySafeCritical]
106             get { return helper.Members; }
107
108             [Fx.Tag.SecurityNote(Critical = "Sets the critical members property.",
109                 Safe = "Protected for write if contract has underlyingType.")]
110             [SecurityCritical]
111             set { helper.Members = value; }
112         }
113
114         public XmlDictionaryString[] ChildElementNamespaces
115         {
116             [Fx.Tag.SecurityNote(Critical = "Sets the critical childElementNamespaces property.",
117                 Safe = "childElementNamespaces only needs to be protected for write; initialized in getter if null.")]
118             [SecuritySafeCritical]
119             get
120             {
121                 if (this.childElementNamespaces == null)
122                 {
123                     lock (this)
124                     {
125                         if (this.childElementNamespaces == null)
126                         {
127                             if (helper.ChildElementNamespaces == null)
128                             {
129                                 XmlDictionaryString[] tempChildElementamespaces = CreateChildElementNamespaces();
130                                 Thread.MemoryBarrier();
131                                 helper.ChildElementNamespaces = tempChildElementamespaces;
132                             }
133                             this.childElementNamespaces = helper.ChildElementNamespaces;
134                         }
135                     }
136                 }
137                 return this.childElementNamespaces;
138             }
139         }
140
141         internal MethodInfo OnSerializing
142         {
143             [Fx.Tag.SecurityNote(Critical = "Fetches the critical onSerializing property.",
144                 Safe = "onSerializing only needs to be protected for write.")]
145             [SecuritySafeCritical]
146             get { return helper.OnSerializing; }
147         }
148
149         internal MethodInfo OnSerialized
150         {
151             [Fx.Tag.SecurityNote(Critical = "Fetches the critical onSerialized property.",
152                 Safe = "onSerialized only needs to be protected for write.")]
153             [SecuritySafeCritical]
154             get { return helper.OnSerialized; }
155         }
156
157         internal MethodInfo OnDeserializing
158         {
159             [Fx.Tag.SecurityNote(Critical = "Fetches the critical onDeserializing property.",
160                 Safe = "onDeserializing only needs to be protected for write.")]
161             [SecuritySafeCritical]
162             get { return helper.OnDeserializing; }
163         }
164
165         internal MethodInfo OnDeserialized
166         {
167             [Fx.Tag.SecurityNote(Critical = "Fetches the critical onDeserialized property.",
168                 Safe = "onDeserialized only needs to be protected for write.")]
169             [SecuritySafeCritical]
170             get { return helper.OnDeserialized; }
171         }
172
173         internal MethodInfo ExtensionDataSetMethod
174         {
175             [Fx.Tag.SecurityNote(Critical = "Fetches the critical extensionDataSetMethod property.",
176                 Safe = "extensionDataSetMethod only needs to be protected for write.")]
177             [SecuritySafeCritical]
178             get { return helper.ExtensionDataSetMethod; }
179         }
180
181         internal override DataContractDictionary KnownDataContracts
182         {
183             [Fx.Tag.SecurityNote(Critical = "Fetches the critical knownDataContracts property.",
184                 Safe = "knownDataContracts only needs to be protected for write.")]
185             [SecuritySafeCritical]
186             get { return helper.KnownDataContracts; }
187
188             [Fx.Tag.SecurityNote(Critical = "Sets the critical knownDataContracts property.",
189                 Safe = "Protected for write if contract has underlyingType.")]
190             [SecurityCritical]
191             set { helper.KnownDataContracts = value; }
192         }
193
194         internal override bool IsISerializable
195         {
196             [Fx.Tag.SecurityNote(Critical = "Fetches the critical isISerializable property.",
197                 Safe = "isISerializable only needs to be protected for write.")]
198             [SecuritySafeCritical]
199             get { return helper.IsISerializable; }
200
201             [Fx.Tag.SecurityNote(Critical = "Sets the critical isISerializable property.",
202                 Safe = "Protected for write if contract has underlyingType.")]
203             [SecurityCritical]
204             set { helper.IsISerializable = value; }
205         }
206
207         internal bool IsNonAttributedType
208         {
209             [Fx.Tag.SecurityNote(Critical = "Fetches the critical IsNonAttributedType property.",
210                 Safe = "IsNonAttributedType only needs to be protected for write.")]
211             [SecuritySafeCritical]
212             get { return helper.IsNonAttributedType; }
213         }
214
215         internal bool HasDataContract
216         {
217             [Fx.Tag.SecurityNote(Critical = "Fetches the critical hasDataContract property.",
218                 Safe = "hasDataContract only needs to be protected for write.")]
219             [SecuritySafeCritical]
220             get { return helper.HasDataContract; }
221         }
222
223         internal bool HasExtensionData
224         {
225             [Fx.Tag.SecurityNote(Critical = "Fetches the critical hasExtensionData property.",
226                 Safe = "hasExtensionData only needs to be protected for write.")]
227             [SecuritySafeCritical]
228             get { return helper.HasExtensionData; }
229         }
230
231         internal string SerializationExceptionMessage
232         {
233             [Fx.Tag.SecurityNote(Critical = "Fetches the critical serializationExceptionMessage property.",
234                 Safe = "serializationExceptionMessage only needs to be protected for write.")]
235             [SecuritySafeCritical]
236             get { return helper.SerializationExceptionMessage; }
237         }
238
239         internal string DeserializationExceptionMessage
240         {
241             [Fx.Tag.SecurityNote(Critical = "Fetches the critical deserializationExceptionMessage property.",
242                 Safe = "deserializationExceptionMessage only needs to be protected for write.")]
243             [SecuritySafeCritical]
244             get { return helper.DeserializationExceptionMessage; }
245         }
246
247         internal bool IsReadOnlyContract
248         {
249             get { return this.DeserializationExceptionMessage != null; }
250         }
251
252         [Fx.Tag.SecurityNote(Critical = "Fetches information about which constructor should be used to initialize ISerializable types.",
253             Safe = "only needs to be protected for write.")]
254         [SecuritySafeCritical]
255         internal ConstructorInfo GetISerializableConstructor()
256         {
257             return helper.GetISerializableConstructor();
258         }
259
260         [Fx.Tag.SecurityNote(Critical = "Fetches information about which constructor should be used to initialize non-attributed types that are valid for serialization.",
261             Safe = "only needs to be protected for write.")]
262         [SecuritySafeCritical]
263         internal ConstructorInfo GetNonAttributedTypeConstructor()
264         {
265             return helper.GetNonAttributedTypeConstructor();
266         }
267
268         internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate
269         {
270             [Fx.Tag.SecurityNote(Critical = "Fetches the critical xmlFormatWriterDelegate property.",
271                 Safe = "xmlFormatWriterDelegate only needs to be protected for write; initialized in getter if null.")]
272             [SecuritySafeCritical]
273             get
274             {
275                 if (helper.XmlFormatWriterDelegate == null)
276                 {
277                     lock (this)
278                     {
279                         if (helper.XmlFormatWriterDelegate == null)
280                         {
281                             XmlFormatClassWriterDelegate tempDelegate = new XmlFormatWriterGenerator().GenerateClassWriter(this);
282                             Thread.MemoryBarrier();
283                             helper.XmlFormatWriterDelegate = tempDelegate;
284                         }
285                     }
286                 }
287                 return helper.XmlFormatWriterDelegate;
288             }
289         }
290
291         internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate
292         {
293             [Fx.Tag.SecurityNote(Critical = "Fetches the critical xmlFormatReaderDelegate property.",
294                 Safe = "xmlFormatReaderDelegate only needs to be protected for write; initialized in getter if null.")]
295             [SecuritySafeCritical]
296             get
297             {
298                 if (helper.XmlFormatReaderDelegate == null)
299                 {
300                     lock (this)
301                     {
302                         if (helper.XmlFormatReaderDelegate == null)
303                         {
304                             if (this.IsReadOnlyContract)
305                             {
306                                 ThrowInvalidDataContractException(helper.DeserializationExceptionMessage, null /*type*/);
307                             }
308                             XmlFormatClassReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateClassReader(this);
309                             Thread.MemoryBarrier();
310                             helper.XmlFormatReaderDelegate = tempDelegate;
311                         }
312                     }
313                 }
314                 return helper.XmlFormatReaderDelegate;
315             }
316         }
317
318         internal static ClassDataContract CreateClassDataContractForKeyValue(Type type, XmlDictionaryString ns, string[] memberNames)
319         {
320             return new ClassDataContract(type, ns, memberNames);
321         }
322
323         internal static void CheckAndAddMember(List<DataMember> members, DataMember memberContract, Dictionary<string, DataMember> memberNamesTable)
324         {
325             DataMember existingMemberContract;
326             if (memberNamesTable.TryGetValue(memberContract.Name, out existingMemberContract))
327             {
328                 Type declaringType = memberContract.MemberInfo.DeclaringType;
329                 DataContract.ThrowInvalidDataContractException(
330                     SR.GetString((declaringType.IsEnum ? SR.DupEnumMemberValue : SR.DupMemberName),
331                         existingMemberContract.MemberInfo.Name,
332                         memberContract.MemberInfo.Name,
333                         DataContract.GetClrTypeFullName(declaringType),
334                         memberContract.Name),
335                     declaringType);
336             }
337             memberNamesTable.Add(memberContract.Name, memberContract);
338             members.Add(memberContract);
339         }
340
341         internal static XmlDictionaryString GetChildNamespaceToDeclare(DataContract dataContract, Type childType, XmlDictionary dictionary)
342         {
343             childType = DataContract.UnwrapNullableType(childType);
344             if (!childType.IsEnum && !Globals.TypeOfIXmlSerializable.IsAssignableFrom(childType)
345                 && DataContract.GetBuiltInDataContract(childType) == null && childType != Globals.TypeOfDBNull)
346             {
347                 string ns = DataContract.GetStableName(childType).Namespace;
348                 if (ns.Length > 0 && ns != dataContract.Namespace.Value)
349                     return dictionary.Add(ns);
350             }
351             return null;
352         }
353
354         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - callers may need to depend on isNonAttributedType for a security decision."
355             + "isNonAttributedType must be calculated correctly."
356             + "IsNonAttributedTypeValidForSerialization is used as part of the isNonAttributedType calculation and is therefore marked with SecurityNote.",
357             Safe = "Does not let caller influence isNonAttributedType calculation; no harm in leaking value.")]
358         // check whether a corresponding update is required in DataContractCriticalHelper.CreateDataContract
359         static internal bool IsNonAttributedTypeValidForSerialization(Type type)
360         {
361             if (type.IsArray)
362                 return false;
363
364             if (type.IsEnum)
365                 return false;
366
367             if (type.IsGenericParameter)
368                 return false;
369
370             if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type))
371                 return false;
372
373             if (type.IsPointer)
374                 return false;
375
376             if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false))
377                 return false;
378
379             Type[] interfaceTypes = type.GetInterfaces();
380             foreach (Type interfaceType in interfaceTypes)
381             {
382                 if (CollectionDataContract.IsCollectionInterface(interfaceType))
383                     return false;
384             }
385
386             if (type.IsSerializable)
387                 return false;
388
389             if (Globals.TypeOfISerializable.IsAssignableFrom(type))
390                 return false;
391
392             if (type.IsDefined(Globals.TypeOfDataContractAttribute, false))
393                 return false;
394
395             if (type == Globals.TypeOfExtensionDataObject)
396                 return false;
397
398             if (type.IsValueType)
399             {
400                 return type.IsVisible;
401             }
402             else
403             {
404                 return (type.IsVisible &&
405                     type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null) != null);
406             }
407         }
408
409         XmlDictionaryString[] CreateChildElementNamespaces()
410         {
411             if (Members == null)
412                 return null;
413
414             XmlDictionaryString[] baseChildElementNamespaces = null;
415             if (this.BaseContract != null)
416                 baseChildElementNamespaces = this.BaseContract.ChildElementNamespaces;
417             int baseChildElementNamespaceCount = (baseChildElementNamespaces != null) ? baseChildElementNamespaces.Length : 0;
418             XmlDictionaryString[] childElementNamespaces = new XmlDictionaryString[Members.Count + baseChildElementNamespaceCount];
419             if (baseChildElementNamespaceCount > 0)
420                 Array.Copy(baseChildElementNamespaces, 0, childElementNamespaces, 0, baseChildElementNamespaces.Length);
421
422             XmlDictionary dictionary = new XmlDictionary();
423             for (int i = 0; i < this.Members.Count; i++)
424             {
425                 childElementNamespaces[i + baseChildElementNamespaceCount] = GetChildNamespaceToDeclare(this, this.Members[i].MemberType, dictionary);
426             }
427
428             return childElementNamespaces;
429         }
430
431         [Fx.Tag.SecurityNote(Critical = "Calls critical method on helper.",
432             Safe = "Doesn't leak anything.")]
433         [SecuritySafeCritical]
434         void EnsureMethodsImported()
435         {
436             helper.EnsureMethodsImported();
437         }
438
439         public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context)
440         {
441             XmlFormatWriterDelegate(xmlWriter, obj, context, this);
442         }
443
444         public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
445         {
446             xmlReader.Read();
447             object o = XmlFormatReaderDelegate(xmlReader, context, MemberNames, MemberNamespaces);
448             xmlReader.ReadEndElement();
449             return o;
450         }
451
452         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - calculates whether this class requires MemberAccessPermission for deserialization."
453             + "Since this information is used to determine whether to give the generated code access "
454             + "permissions to private members, any changes to the logic should be reviewed.")]
455         internal bool RequiresMemberAccessForRead(SecurityException securityException)
456         {
457             EnsureMethodsImported();
458
459             if (!IsTypeVisible(UnderlyingType))
460             {
461                 if (securityException != null)
462                 {
463                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
464                         new SecurityException(SR.GetString(
465                                 SR.PartialTrustDataContractTypeNotPublic,
466                                 DataContract.GetClrTypeFullName(UnderlyingType)),
467                             securityException));
468                 }
469                 return true;
470             }
471
472             if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForRead(securityException))
473                 return true;
474
475             if (ConstructorRequiresMemberAccess(GetISerializableConstructor()))
476             {
477                 if (securityException != null)
478                 {
479                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
480                         new SecurityException(SR.GetString(
481                                 SR.PartialTrustISerializableNoPublicConstructor,
482                                 DataContract.GetClrTypeFullName(UnderlyingType)),
483                             securityException));
484                 }
485                 return true;
486             }
487
488
489             if (ConstructorRequiresMemberAccess(GetNonAttributedTypeConstructor()))
490             {
491                 if (securityException != null)
492                 {
493                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
494                         new SecurityException(SR.GetString(
495                                 SR.PartialTrustNonAttributedSerializableTypeNoPublicConstructor,
496                                 DataContract.GetClrTypeFullName(UnderlyingType)),
497                             securityException));
498                 }
499                 return true;
500             }
501
502
503             if (MethodRequiresMemberAccess(this.OnDeserializing))
504             {
505                 if (securityException != null)
506                 {
507                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
508                         new SecurityException(SR.GetString(
509                                 SR.PartialTrustDataContractOnDeserializingNotPublic,
510                                 DataContract.GetClrTypeFullName(UnderlyingType),
511                                 this.OnDeserializing.Name),
512                             securityException));
513                 }
514                 return true;
515             }
516
517             if (MethodRequiresMemberAccess(this.OnDeserialized))
518             {
519                 if (securityException != null)
520                 {
521                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
522                         new SecurityException(SR.GetString(
523                                 SR.PartialTrustDataContractOnDeserializedNotPublic,
524                                 DataContract.GetClrTypeFullName(UnderlyingType),
525                                 this.OnDeserialized.Name),
526                             securityException));
527                 }
528                 return true;
529             }
530
531             if (this.Members != null)
532             {
533                 for (int i = 0; i < this.Members.Count; i++)
534                 {
535                     if (this.Members[i].RequiresMemberAccessForSet())
536                     {
537                         if (securityException != null)
538                         {
539                             if (this.Members[i].MemberInfo is FieldInfo)
540                             {
541                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
542                                     new SecurityException(SR.GetString(
543                                             SR.PartialTrustDataContractFieldSetNotPublic,
544                                             DataContract.GetClrTypeFullName(UnderlyingType),
545                                             this.Members[i].MemberInfo.Name),
546                                         securityException));
547                             }
548                             else
549                             {
550                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
551                                     new SecurityException(SR.GetString(
552                                             SR.PartialTrustDataContractPropertySetNotPublic,
553                                             DataContract.GetClrTypeFullName(UnderlyingType),
554                                             this.Members[i].MemberInfo.Name),
555                                         securityException));
556                             }
557                         }
558                         return true;
559                     }
560                 }
561             }
562
563             return false;
564         }
565
566         [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - calculates whether this class requires MemberAccessPermission for serialization."
567             + " Since this information is used to determine whether to give the generated code access"
568             + " permissions to private members, any changes to the logic should be reviewed.")]
569         internal bool RequiresMemberAccessForWrite(SecurityException securityException)
570         {
571
572 #if DISABLE_CAS_USE
573             return true;
574 #else
575             EnsureMethodsImported();
576
577             if (!IsTypeVisible(UnderlyingType))
578             {
579                 if (securityException != null)
580                 {
581                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
582                         new SecurityException(SR.GetString(
583                                 SR.PartialTrustDataContractTypeNotPublic,
584                                 DataContract.GetClrTypeFullName(UnderlyingType)),
585                             securityException));
586                 }
587                 return true;
588             }
589
590             if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForWrite(securityException))
591                 return true;
592
593             if (MethodRequiresMemberAccess(this.OnSerializing))
594             {
595                 if (securityException != null)
596                 {
597                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
598                         new SecurityException(SR.GetString(
599                                 SR.PartialTrustDataContractOnSerializingNotPublic,
600                                 DataContract.GetClrTypeFullName(this.UnderlyingType),
601                                 this.OnSerializing.Name),
602                             securityException));
603                 }
604                 return true;
605             }
606
607             if (MethodRequiresMemberAccess(this.OnSerialized))
608             {
609                 if (securityException != null)
610                 {
611                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
612                         new SecurityException(SR.GetString(
613                                 SR.PartialTrustDataContractOnSerializedNotPublic,
614                                 DataContract.GetClrTypeFullName(UnderlyingType),
615                                 this.OnSerialized.Name),
616                             securityException));
617                 }
618                 return true;
619             }
620
621             if (this.Members != null)
622             {
623                 for (int i = 0; i < this.Members.Count; i++)
624                 {
625                     if (this.Members[i].RequiresMemberAccessForGet())
626                     {
627                         if (securityException != null)
628                         {
629                             if (this.Members[i].MemberInfo is FieldInfo)
630                             {
631                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
632                                     new SecurityException(SR.GetString(
633                                             SR.PartialTrustDataContractFieldGetNotPublic,
634                                             DataContract.GetClrTypeFullName(UnderlyingType),
635                                             this.Members[i].MemberInfo.Name),
636                                         securityException));
637                             }
638                             else
639                             {
640                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
641                                     new SecurityException(SR.GetString(
642                                             SR.PartialTrustDataContractPropertyGetNotPublic,
643                                             DataContract.GetClrTypeFullName(UnderlyingType),
644                                             this.Members[i].MemberInfo.Name),
645                                         securityException));
646                             }
647                         }
648                         return true;
649                     }
650                 }
651             }
652
653             return false;
654 #endif
655         }
656
657         [Fx.Tag.SecurityNote(Critical = "Holds all state used for (de)serializing classes."
658             + " Since the data is cached statically, we lock down access to it.")]
659         [SecurityCritical(SecurityCriticalScope.Everything)]
660         class ClassDataContractCriticalHelper : DataContract.DataContractCriticalHelper
661         {
662             ClassDataContract baseContract;
663             List<DataMember> members;
664             MethodInfo onSerializing, onSerialized;
665             MethodInfo onDeserializing, onDeserialized;
666             MethodInfo extensionDataSetMethod;
667             DataContractDictionary knownDataContracts;
668             string serializationExceptionMessage;
669             bool isISerializable;
670             bool isKnownTypeAttributeChecked;
671             bool isMethodChecked;
672             bool hasExtensionData;
673
674             [Fx.Tag.SecurityNote(Miscellaneous = "in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and hasDataContract.")]
675             bool isNonAttributedType;
676
677             [Fx.Tag.SecurityNote(Miscellaneous = "in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and isNonAttributedType.")]
678             bool hasDataContract;
679
680             XmlDictionaryString[] childElementNamespaces;
681             XmlFormatClassReaderDelegate xmlFormatReaderDelegate;
682             XmlFormatClassWriterDelegate xmlFormatWriterDelegate;
683
684             public XmlDictionaryString[] ContractNamespaces;
685             public XmlDictionaryString[] MemberNames;
686             public XmlDictionaryString[] MemberNamespaces;
687
688             internal ClassDataContractCriticalHelper()
689                 : base()
690             {
691             }
692
693             internal ClassDataContractCriticalHelper(Type type)
694                 : base(type)
695             {
696                 XmlQualifiedName stableName = GetStableNameAndSetHasDataContract(type);
697                 if (type == Globals.TypeOfDBNull)
698                 {
699                     this.StableName = stableName;
700                     this.members = new List<DataMember>();
701                     XmlDictionary dictionary = new XmlDictionary(2);
702                     this.Name = dictionary.Add(StableName.Name);
703                     this.Namespace = dictionary.Add(StableName.Namespace);
704                     this.ContractNamespaces = this.MemberNames = this.MemberNamespaces = new XmlDictionaryString[] { };
705                     EnsureMethodsImported();
706                     return;
707                 }
708                 Type baseType = type.BaseType;
709                 this.isISerializable = (Globals.TypeOfISerializable.IsAssignableFrom(type));
710                 SetIsNonAttributedType(type);
711                 if (this.isISerializable)
712                 {
713                     if (HasDataContract)
714                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.ISerializableCannotHaveDataContract, DataContract.GetClrTypeFullName(type))));
715                     if (baseType != null && !(baseType.IsSerializable && Globals.TypeOfISerializable.IsAssignableFrom(baseType)))
716                         baseType = null;
717                 }
718                 this.IsValueType = type.IsValueType;
719                 if (baseType != null && baseType != Globals.TypeOfObject && baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri)
720                 {
721                     DataContract baseContract = DataContract.GetDataContract(baseType);
722                     if (baseContract is CollectionDataContract)
723                         this.BaseContract = ((CollectionDataContract)baseContract).SharedTypeContract as ClassDataContract;
724                     else
725                         this.BaseContract = baseContract as ClassDataContract;
726                     if (this.BaseContract != null && this.BaseContract.IsNonAttributedType && !this.isNonAttributedType)
727                     {
728                         throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError
729                             (new InvalidDataContractException(SR.GetString(SR.AttributedTypesCannotInheritFromNonAttributedSerializableTypes,
730                             DataContract.GetClrTypeFullName(type), DataContract.GetClrTypeFullName(baseType))));
731                     }
732                 }
733                 else
734                     this.BaseContract = null;
735                 hasExtensionData = (Globals.TypeOfIExtensibleDataObject.IsAssignableFrom(type));
736                 if (hasExtensionData && !HasDataContract && !IsNonAttributedType)
737                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.OnlyDataContractTypesCanHaveExtensionData, DataContract.GetClrTypeFullName(type))));
738                 if (this.isISerializable)
739                     SetDataContractName(stableName);
740                 else
741                 {
742                     this.StableName = stableName;
743                     ImportDataMembers();
744                     XmlDictionary dictionary = new XmlDictionary(2 + Members.Count);
745                     Name = dictionary.Add(StableName.Name);
746                     Namespace = dictionary.Add(StableName.Namespace);
747
748                     int baseMemberCount = 0;
749                     int baseContractCount = 0;
750                     if (BaseContract == null)
751                     {
752                         MemberNames = new XmlDictionaryString[Members.Count];
753                         MemberNamespaces = new XmlDictionaryString[Members.Count];
754                         ContractNamespaces = new XmlDictionaryString[1];
755                     }
756                     else
757                     {
758                         if (BaseContract.IsReadOnlyContract)
759                         {
760                             this.serializationExceptionMessage = BaseContract.SerializationExceptionMessage;
761                         }
762                         baseMemberCount = BaseContract.MemberNames.Length;
763                         MemberNames = new XmlDictionaryString[Members.Count + baseMemberCount];
764                         Array.Copy(BaseContract.MemberNames, MemberNames, baseMemberCount);
765                         MemberNamespaces = new XmlDictionaryString[Members.Count + baseMemberCount];
766                         Array.Copy(BaseContract.MemberNamespaces, MemberNamespaces, baseMemberCount);
767                         baseContractCount = BaseContract.ContractNamespaces.Length;
768                         ContractNamespaces = new XmlDictionaryString[1 + baseContractCount];
769                         Array.Copy(BaseContract.ContractNamespaces, ContractNamespaces, baseContractCount);
770                     }
771                     ContractNamespaces[baseContractCount] = Namespace;
772                     for (int i = 0; i < Members.Count; i++)
773                     {
774                         MemberNames[i + baseMemberCount] = dictionary.Add(Members[i].Name);
775                         MemberNamespaces[i + baseMemberCount] = Namespace;
776                     }
777                 }
778                 EnsureMethodsImported();
779             }
780
781             internal ClassDataContractCriticalHelper(Type type, XmlDictionaryString ns, string[] memberNames)
782                 : base(type)
783             {
784                 this.StableName = new XmlQualifiedName(GetStableNameAndSetHasDataContract(type).Name, ns.Value);
785                 ImportDataMembers();
786                 XmlDictionary dictionary = new XmlDictionary(1 + Members.Count);
787                 Name = dictionary.Add(StableName.Name);
788                 Namespace = ns;
789                 ContractNamespaces = new XmlDictionaryString[] { Namespace };
790                 MemberNames = new XmlDictionaryString[Members.Count];
791                 MemberNamespaces = new XmlDictionaryString[Members.Count];
792                 for (int i = 0; i < Members.Count; i++)
793                 {
794                     Members[i].Name = memberNames[i];
795                     MemberNames[i] = dictionary.Add(Members[i].Name);
796                     MemberNamespaces[i] = Namespace;
797                 }
798                 EnsureMethodsImported();
799             }
800
801             void EnsureIsReferenceImported(Type type)
802             {
803                 DataContractAttribute dataContractAttribute;
804                 bool isReference = false;
805                 bool hasDataContractAttribute = TryGetDCAttribute(type, out dataContractAttribute);
806
807                 if (BaseContract != null)
808                 {
809                     if (hasDataContractAttribute && dataContractAttribute.IsReferenceSetExplicit)
810                     {
811                         bool baseIsReference = this.BaseContract.IsReference;
812                         if ((baseIsReference && !dataContractAttribute.IsReference) ||
813                             (!baseIsReference && dataContractAttribute.IsReference))
814                         {
815                             DataContract.ThrowInvalidDataContractException(
816                                     SR.GetString(SR.InconsistentIsReference,
817                                         DataContract.GetClrTypeFullName(type),
818                                         dataContractAttribute.IsReference,
819                                         DataContract.GetClrTypeFullName(this.BaseContract.UnderlyingType),
820                                         this.BaseContract.IsReference),
821                                     type);
822                         }
823                         else
824                         {
825                             isReference = dataContractAttribute.IsReference;
826                         }
827                     }
828                     else
829                     {
830                         isReference = this.BaseContract.IsReference;
831                     }
832                 }
833                 else if (hasDataContractAttribute)
834                 {
835                     if (dataContractAttribute.IsReference)
836                         isReference = dataContractAttribute.IsReference;
837                 }
838
839                 if (isReference && type.IsValueType)
840                 {
841                     DataContract.ThrowInvalidDataContractException(
842                             SR.GetString(SR.ValueTypeCannotHaveIsReference,
843                                 DataContract.GetClrTypeFullName(type),
844                                 true,
845                                 false),
846                             type);
847                     return;
848                 }
849
850                 this.IsReference = isReference;
851             }
852
853             void ImportDataMembers()
854             {
855                 Type type = this.UnderlyingType;
856                 EnsureIsReferenceImported(type);
857                 List<DataMember> tempMembers = new List<DataMember>();
858                 Dictionary<string, DataMember> memberNamesTable = new Dictionary<string, DataMember>();
859
860                 MemberInfo[] memberInfos;
861                 if (this.isNonAttributedType)
862                 {
863                     memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
864                 }
865                 else
866                 {
867                     memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
868                 }
869
870                 for (int i = 0; i < memberInfos.Length; i++)
871                 {
872                     MemberInfo member = memberInfos[i];
873                     if (HasDataContract)
874                     {
875                         object[] memberAttributes = member.GetCustomAttributes(typeof(DataMemberAttribute), false);
876                         if (memberAttributes != null && memberAttributes.Length > 0)
877                         {
878                             if (memberAttributes.Length > 1)
879                                 ThrowInvalidDataContractException(SR.GetString(SR.TooManyDataMembers, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name));
880
881                             DataMember memberContract = new DataMember(member);
882
883                             if (member.MemberType == MemberTypes.Property)
884                             {
885                                 PropertyInfo property = (PropertyInfo)member;
886
887                                 MethodInfo getMethod = property.GetGetMethod(true);
888                                 if (getMethod != null && IsMethodOverriding(getMethod))
889                                     continue;
890                                 MethodInfo setMethod = property.GetSetMethod(true);
891                                 if (setMethod != null && IsMethodOverriding(setMethod))
892                                     continue;
893                                 if (getMethod == null)
894                                     ThrowInvalidDataContractException(SR.GetString(SR.NoGetMethodForProperty, property.DeclaringType, property.Name));
895                                 if (setMethod == null)
896                                 {
897                                     if (!SetIfGetOnlyCollection(memberContract, skipIfReadOnlyContract: false))
898                                     {
899                                         this.serializationExceptionMessage = SR.GetString(SR.NoSetMethodForProperty, property.DeclaringType, property.Name);
900                                     }
901                                 }
902                                 if (getMethod.GetParameters().Length > 0)
903                                     ThrowInvalidDataContractException(SR.GetString(SR.IndexedPropertyCannotBeSerialized, property.DeclaringType, property.Name));
904                             }
905                             else if (member.MemberType != MemberTypes.Field)
906                                 ThrowInvalidDataContractException(SR.GetString(SR.InvalidMember, DataContract.GetClrTypeFullName(type), member.Name));
907
908                             DataMemberAttribute memberAttribute = (DataMemberAttribute)memberAttributes[0];
909                             if (memberAttribute.IsNameSetExplicit)
910                             {
911                                 if (memberAttribute.Name == null || memberAttribute.Name.Length == 0)
912                                     ThrowInvalidDataContractException(SR.GetString(SR.InvalidDataMemberName, member.Name, DataContract.GetClrTypeFullName(type)));
913                                 memberContract.Name = memberAttribute.Name;
914                             }
915                             else
916                                 memberContract.Name = member.Name;
917
918                             memberContract.Name = DataContract.EncodeLocalName(memberContract.Name);
919                             memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType);
920                             memberContract.IsRequired = memberAttribute.IsRequired;
921                             if (memberAttribute.IsRequired && this.IsReference)
922                             {
923                                 ThrowInvalidDataContractException(
924                                     SR.GetString(SR.IsRequiredDataMemberOnIsReferenceDataContractType,
925                                     DataContract.GetClrTypeFullName(member.DeclaringType),
926                                     member.Name, true), type);
927                             }
928                             memberContract.EmitDefaultValue = memberAttribute.EmitDefaultValue;
929                             memberContract.Order = memberAttribute.Order;
930                             CheckAndAddMember(tempMembers, memberContract, memberNamesTable);
931                         }
932                     }
933                     else if (this.isNonAttributedType)
934                     {
935                         FieldInfo field = member as FieldInfo;
936                         PropertyInfo property = member as PropertyInfo;
937                         if ((field == null && property == null) || (field != null && field.IsInitOnly))
938                             continue;
939
940                         object[] memberAttributes = member.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), false);
941                         if (memberAttributes != null && memberAttributes.Length > 0)
942                         {
943                             if (memberAttributes.Length > 1)
944                                 ThrowInvalidDataContractException(SR.GetString(SR.TooManyIgnoreDataMemberAttributes, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name));
945                             else
946                                 continue;
947                         }
948                         DataMember memberContract = new DataMember(member);
949                         if (property != null)
950                         {
951                             MethodInfo getMethod = property.GetGetMethod();
952                             if (getMethod == null || IsMethodOverriding(getMethod) || getMethod.GetParameters().Length > 0)
953                                 continue;
954
955                             MethodInfo setMethod = property.GetSetMethod(true);
956                             if (setMethod == null)
957                             {
958                                 // if the collection doesn't have the 'Add' method, we will skip it, for compatibility with 4.0
959                                 if (!SetIfGetOnlyCollection(memberContract, skipIfReadOnlyContract: true))
960                                     continue;
961                             }
962                             else
963                             {
964                                 if (!setMethod.IsPublic || IsMethodOverriding(setMethod))
965                                     continue;
966                             }
967
968                             //skip ExtensionData member of type ExtensionDataObject if IExtensibleDataObject is implemented in non-attributed type
969                             if (this.hasExtensionData && memberContract.MemberType == Globals.TypeOfExtensionDataObject
970                                 && member.Name == Globals.ExtensionDataObjectPropertyName)
971                                 continue;
972                         }
973
974                         memberContract.Name = DataContract.EncodeLocalName(member.Name);
975                         memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType);
976                         CheckAndAddMember(tempMembers, memberContract, memberNamesTable);
977                     }
978                     else
979                     {
980                         FieldInfo field = member as FieldInfo;
981                         if (field != null && !field.IsNotSerialized)
982                         {
983                             DataMember memberContract = new DataMember(member);
984
985                             memberContract.Name = DataContract.EncodeLocalName(member.Name);
986                             object[] optionalFields = field.GetCustomAttributes(Globals.TypeOfOptionalFieldAttribute, false);
987                             if (optionalFields == null || optionalFields.Length == 0)
988                             {
989                                 if (this.IsReference)
990                                 {
991                                     ThrowInvalidDataContractException(
992                                         SR.GetString(SR.NonOptionalFieldMemberOnIsReferenceSerializableType,
993                                         DataContract.GetClrTypeFullName(member.DeclaringType),
994                                         member.Name, true), type);
995                                 }
996                                 memberContract.IsRequired = true;
997                             }
998                             memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType);
999                             CheckAndAddMember(tempMembers, memberContract, memberNamesTable);
1000                         }
1001                     }
1002                 }
1003                 if (tempMembers.Count > 1)
1004                     tempMembers.Sort(DataMemberComparer.Singleton);
1005
1006                 SetIfMembersHaveConflict(tempMembers);
1007
1008                 Thread.MemoryBarrier();
1009                 members = tempMembers;
1010             }
1011
1012             bool SetIfGetOnlyCollection(DataMember memberContract, bool skipIfReadOnlyContract)
1013             {
1014                 //OK to call IsCollection here since the use of surrogated collection types is not supported in get-only scenarios
1015                 if (CollectionDataContract.IsCollection(memberContract.MemberType, false /*isConstructorRequired*/, skipIfReadOnlyContract) && !memberContract.MemberType.IsValueType)
1016                 {
1017                     memberContract.IsGetOnlyCollection = true;
1018                     return true;
1019                 }
1020                 return false;
1021             }
1022
1023             void SetIfMembersHaveConflict(List<DataMember> members)
1024             {
1025                 if (BaseContract == null)
1026                     return;
1027
1028                 int baseTypeIndex = 0;
1029                 List<Member> membersInHierarchy = new List<Member>();
1030                 foreach (DataMember member in members)
1031                 {
1032                     membersInHierarchy.Add(new Member(member, this.StableName.Namespace, baseTypeIndex));
1033                 }
1034                 ClassDataContract currContract = BaseContract;
1035                 while (currContract != null)
1036                 {
1037                     baseTypeIndex++;
1038                     foreach (DataMember member in currContract.Members)
1039                     {
1040                         membersInHierarchy.Add(new Member(member, currContract.StableName.Namespace, baseTypeIndex));
1041                     }
1042                     currContract = currContract.BaseContract;
1043                 }
1044
1045                 IComparer<Member> comparer = DataMemberConflictComparer.Singleton;
1046                 membersInHierarchy.Sort(comparer);
1047
1048                 for (int i = 0; i < membersInHierarchy.Count - 1; i++)
1049                 {
1050                     int startIndex = i;
1051                     int endIndex = i;
1052                     bool hasConflictingType = false;
1053                     while (endIndex < membersInHierarchy.Count - 1
1054                         && String.CompareOrdinal(membersInHierarchy[endIndex].member.Name, membersInHierarchy[endIndex + 1].member.Name) == 0
1055                         && String.CompareOrdinal(membersInHierarchy[endIndex].ns, membersInHierarchy[endIndex + 1].ns) == 0)
1056                     {
1057                         membersInHierarchy[endIndex].member.ConflictingMember = membersInHierarchy[endIndex + 1].member;
1058                         if (!hasConflictingType)
1059                         {
1060                             if (membersInHierarchy[endIndex + 1].member.HasConflictingNameAndType)
1061                             {
1062                                 hasConflictingType = true;
1063                             }
1064                             else
1065                             {
1066                                 hasConflictingType = (membersInHierarchy[endIndex].member.MemberType != membersInHierarchy[endIndex + 1].member.MemberType);
1067                             }
1068                         }
1069                         endIndex++;
1070                     }
1071
1072                     if (hasConflictingType)
1073                     {
1074                         for (int j = startIndex; j <= endIndex; j++)
1075                         {
1076                             membersInHierarchy[j].member.HasConflictingNameAndType = true;
1077                         }
1078                     }
1079
1080                     i = endIndex + 1;
1081                 }
1082             }
1083
1084             [Fx.Tag.SecurityNote(Critical = "Sets the critical hasDataContract field.",
1085                 Safe = "Uses a trusted critical API (DataContract.GetStableName) to calculate the value, does not accept the value from the caller.")]
1086             [SecuritySafeCritical]
1087             XmlQualifiedName GetStableNameAndSetHasDataContract(Type type)
1088             {
1089                 return DataContract.GetStableName(type, out this.hasDataContract);
1090             }
1091
1092             [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - callers may need to depend on isNonAttributedType for a security decision."
1093                 + "isNonAttributedType must be calculated correctly."
1094                 + "SetIsNonAttributedType should not be called before GetStableNameAndSetHasDataContract since it is dependent on the correct calculation of hasDataContract.",
1095                 Safe = "Does not let caller influence isNonAttributedType calculation; no harm in leaking value.")]
1096             void SetIsNonAttributedType(Type type)
1097             {
1098                 this.isNonAttributedType = !type.IsSerializable && !this.hasDataContract && IsNonAttributedTypeValidForSerialization(type);
1099             }
1100
1101             static bool IsMethodOverriding(MethodInfo method)
1102             {
1103                 return method.IsVirtual && ((method.Attributes & MethodAttributes.NewSlot) == 0);
1104             }
1105
1106             internal void EnsureMethodsImported()
1107             {
1108                 if (!isMethodChecked && UnderlyingType != null)
1109                 {
1110                     lock (this)
1111                     {
1112                         if (!isMethodChecked)
1113                         {
1114                             Type type = this.UnderlyingType;
1115                             MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1116                             for (int i = 0; i < methods.Length; i++)
1117                             {
1118                                 MethodInfo method = methods[i];
1119                                 Type prevAttributeType = null;
1120                                 ParameterInfo[] parameters = method.GetParameters();
1121                                 if (HasExtensionData && IsValidExtensionDataSetMethod(method, parameters))
1122                                 {
1123                                     if (method.Name == Globals.ExtensionDataSetExplicitMethod || !method.IsPublic)
1124                                         extensionDataSetMethod = XmlFormatGeneratorStatics.ExtensionDataSetExplicitMethodInfo;
1125                                     else
1126                                         extensionDataSetMethod = method;
1127                                 }
1128                                 if (IsValidCallback(method, parameters, Globals.TypeOfOnSerializingAttribute, onSerializing, ref prevAttributeType))
1129                                     onSerializing = method;
1130                                 if (IsValidCallback(method, parameters, Globals.TypeOfOnSerializedAttribute, onSerialized, ref prevAttributeType))
1131                                     onSerialized = method;
1132                                 if (IsValidCallback(method, parameters, Globals.TypeOfOnDeserializingAttribute, onDeserializing, ref prevAttributeType))
1133                                     onDeserializing = method;
1134                                 if (IsValidCallback(method, parameters, Globals.TypeOfOnDeserializedAttribute, onDeserialized, ref prevAttributeType))
1135                                     onDeserialized = method;
1136                             }
1137                             Thread.MemoryBarrier();
1138                             isMethodChecked = true;
1139                         }
1140                     }
1141                 }
1142             }
1143
1144             bool IsValidExtensionDataSetMethod(MethodInfo method, ParameterInfo[] parameters)
1145             {
1146                 if (method.Name == Globals.ExtensionDataSetExplicitMethod || method.Name == Globals.ExtensionDataSetMethod)
1147                 {
1148                     if (extensionDataSetMethod != null)
1149                         ThrowInvalidDataContractException(SR.GetString(SR.DuplicateExtensionDataSetMethod, method, extensionDataSetMethod, DataContract.GetClrTypeFullName(method.DeclaringType)));
1150                     if (method.ReturnType != Globals.TypeOfVoid)
1151                         DataContract.ThrowInvalidDataContractException(SR.GetString(SR.ExtensionDataSetMustReturnVoid, DataContract.GetClrTypeFullName(method.DeclaringType), method), method.DeclaringType);
1152                     if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != Globals.TypeOfExtensionDataObject)
1153                         DataContract.ThrowInvalidDataContractException(SR.GetString(SR.ExtensionDataSetParameterInvalid, DataContract.GetClrTypeFullName(method.DeclaringType), method, Globals.TypeOfExtensionDataObject), method.DeclaringType);
1154                     return true;
1155                 }
1156                 return false;
1157             }
1158
1159             static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo currentCallback, ref Type prevAttributeType)
1160             {
1161                 if (method.IsDefined(attributeType, false))
1162                 {
1163                     if (currentCallback != null)
1164                         DataContract.ThrowInvalidDataContractException(SR.GetString(SR.DuplicateCallback, method, currentCallback, DataContract.GetClrTypeFullName(method.DeclaringType), attributeType), method.DeclaringType);
1165                     else if (prevAttributeType != null)
1166                         DataContract.ThrowInvalidDataContractException(SR.GetString(SR.DuplicateAttribute, prevAttributeType, attributeType, DataContract.GetClrTypeFullName(method.DeclaringType), method), method.DeclaringType);
1167                     else if (method.IsVirtual)
1168                         DataContract.ThrowInvalidDataContractException(SR.GetString(SR.CallbacksCannotBeVirtualMethods, method, DataContract.GetClrTypeFullName(method.DeclaringType), attributeType), method.DeclaringType);
1169                     else
1170                     {
1171                         if (method.ReturnType != Globals.TypeOfVoid)
1172                             DataContract.ThrowInvalidDataContractException(SR.GetString(SR.CallbackMustReturnVoid, DataContract.GetClrTypeFullName(method.DeclaringType), method), method.DeclaringType);
1173                         if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != Globals.TypeOfStreamingContext)
1174                             DataContract.ThrowInvalidDataContractException(SR.GetString(SR.CallbackParameterInvalid, DataContract.GetClrTypeFullName(method.DeclaringType), method, Globals.TypeOfStreamingContext), method.DeclaringType);
1175
1176                         prevAttributeType = attributeType;
1177                     }
1178                     return true;
1179                 }
1180                 return false;
1181             }
1182
1183             internal ClassDataContract BaseContract
1184             {
1185                 get { return baseContract; }
1186                 set
1187                 {
1188                     baseContract = value;
1189                     if (baseContract != null && IsValueType)
1190                         ThrowInvalidDataContractException(SR.GetString(SR.ValueTypeCannotHaveBaseType, StableName.Name, StableName.Namespace, baseContract.StableName.Name, baseContract.StableName.Namespace));
1191                 }
1192             }
1193
1194             internal List<DataMember> Members
1195             {
1196                 get { return members; }
1197                 set { members = value; }
1198             }
1199
1200             internal MethodInfo OnSerializing
1201             {
1202                 get
1203                 {
1204                     EnsureMethodsImported();
1205                     return onSerializing;
1206                 }
1207             }
1208
1209             internal MethodInfo OnSerialized
1210             {
1211                 get
1212                 {
1213                     EnsureMethodsImported();
1214                     return onSerialized;
1215                 }
1216             }
1217
1218             internal MethodInfo OnDeserializing
1219             {
1220                 get
1221                 {
1222                     EnsureMethodsImported();
1223                     return onDeserializing;
1224                 }
1225             }
1226
1227             internal MethodInfo OnDeserialized
1228             {
1229                 get
1230                 {
1231                     EnsureMethodsImported();
1232                     return onDeserialized;
1233                 }
1234             }
1235
1236             internal MethodInfo ExtensionDataSetMethod
1237             {
1238                 get
1239                 {
1240                     EnsureMethodsImported();
1241                     return extensionDataSetMethod;
1242                 }
1243             }
1244
1245             internal override DataContractDictionary KnownDataContracts
1246             {
1247                 get
1248                 {
1249                     if (!isKnownTypeAttributeChecked && UnderlyingType != null)
1250                     {
1251                         lock (this)
1252                         {
1253                             if (!isKnownTypeAttributeChecked)
1254                             {
1255                                 knownDataContracts = DataContract.ImportKnownTypeAttributes(this.UnderlyingType);
1256                                 Thread.MemoryBarrier();
1257                                 isKnownTypeAttributeChecked = true;
1258                             }
1259                         }
1260                     }
1261                     return knownDataContracts;
1262                 }
1263                 set { knownDataContracts = value; }
1264             }
1265
1266             internal string SerializationExceptionMessage
1267             {
1268                 get { return serializationExceptionMessage; }
1269             }
1270
1271             internal string DeserializationExceptionMessage
1272             {
1273                 get
1274                 {
1275                     if (serializationExceptionMessage == null)
1276                     {
1277                         return null;
1278                     }
1279                     else
1280                     {
1281                         return SR.GetString(SR.ReadOnlyClassDeserialization, this.serializationExceptionMessage);
1282                     }
1283                 }
1284             }
1285
1286             internal override bool IsISerializable
1287             {
1288                 get { return isISerializable; }
1289                 set { isISerializable = value; }
1290             }
1291
1292             internal bool HasDataContract
1293             {
1294                 get { return hasDataContract; }
1295             }
1296
1297             internal bool HasExtensionData
1298             {
1299                 get { return hasExtensionData; }
1300             }
1301
1302             internal bool IsNonAttributedType
1303             {
1304                 get { return isNonAttributedType; }
1305             }
1306
1307             internal ConstructorInfo GetISerializableConstructor()
1308             {
1309                 if (!IsISerializable)
1310                     return null;
1311
1312                 ConstructorInfo ctor = UnderlyingType.GetConstructor(Globals.ScanAllMembers, null, SerInfoCtorArgs, null);
1313                 if (ctor == null)
1314                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.SerializationInfo_ConstructorNotFound, DataContract.GetClrTypeFullName(UnderlyingType))));
1315
1316                 return ctor;
1317             }
1318
1319             internal ConstructorInfo GetNonAttributedTypeConstructor()
1320             {
1321                 if (!this.IsNonAttributedType)
1322                     return null;
1323
1324                 Type type = UnderlyingType;
1325
1326                 if (type.IsValueType)
1327                     return null;
1328
1329                 ConstructorInfo ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
1330                 if (ctor == null)
1331                     throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.NonAttributedSerializableTypesMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type))));
1332
1333                 return ctor;
1334             }
1335
1336             internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate
1337             {
1338                 get { return xmlFormatWriterDelegate; }
1339                 set { xmlFormatWriterDelegate = value; }
1340             }
1341
1342             internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate
1343             {
1344                 get { return xmlFormatReaderDelegate; }
1345                 set { xmlFormatReaderDelegate = value; }
1346             }
1347
1348             public XmlDictionaryString[] ChildElementNamespaces
1349             {
1350                 get { return childElementNamespaces; }
1351                 set { childElementNamespaces = value; }
1352             }
1353
1354             static Type[] serInfoCtorArgs;
1355             static Type[] SerInfoCtorArgs
1356             {
1357                 get
1358                 {
1359                     if (serInfoCtorArgs == null)
1360                         serInfoCtorArgs = new Type[] { typeof(SerializationInfo), typeof(StreamingContext) };
1361                     return serInfoCtorArgs;
1362                 }
1363             }
1364
1365             internal struct Member
1366             {
1367                 internal Member(DataMember member, string ns, int baseTypeIndex)
1368                 {
1369                     this.member = member;
1370                     this.ns = ns;
1371                     this.baseTypeIndex = baseTypeIndex;
1372                 }
1373                 internal DataMember member;
1374                 internal string ns;
1375                 internal int baseTypeIndex;
1376             }
1377
1378             internal class DataMemberConflictComparer : IComparer<Member>
1379             {
1380                 public int Compare(Member x, Member y)
1381                 {
1382                     int nsCompare = String.CompareOrdinal(x.ns, y.ns);
1383                     if (nsCompare != 0)
1384                         return nsCompare;
1385
1386                     int nameCompare = String.CompareOrdinal(x.member.Name, y.member.Name);
1387                     if (nameCompare != 0)
1388                         return nameCompare;
1389
1390                     return x.baseTypeIndex - y.baseTypeIndex;
1391                 }
1392
1393                 internal static DataMemberConflictComparer Singleton = new DataMemberConflictComparer();
1394             }
1395
1396         }
1397
1398         [Fx.Tag.SecurityNote(Critical = "Sets critical properties on ClassDataContract .",
1399             Safe = "Called during schema import/code generation.")]
1400         [SecuritySafeCritical]
1401         internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary<DataContract, DataContract> boundContracts)
1402         {
1403             Type type = UnderlyingType;
1404             if (!type.IsGenericType || !type.ContainsGenericParameters)
1405                 return this;
1406
1407             lock (this)
1408             {
1409                 DataContract boundContract;
1410                 if (boundContracts.TryGetValue(this, out boundContract))
1411                     return boundContract;
1412
1413                 ClassDataContract boundClassContract = new ClassDataContract();
1414                 boundContracts.Add(this, boundClassContract);
1415                 XmlQualifiedName stableName;
1416                 object[] genericParams;
1417                 if (type.IsGenericTypeDefinition)
1418                 {
1419                     stableName = this.StableName;
1420                     genericParams = paramContracts;
1421                 }
1422                 else
1423                 {
1424                     //partial Generic: Construct stable name from its open generic type definition
1425                     stableName = DataContract.GetStableName(type.GetGenericTypeDefinition());
1426                     Type[] paramTypes = type.GetGenericArguments();
1427                     genericParams = new object[paramTypes.Length];
1428                     for (int i = 0; i < paramTypes.Length; i++)
1429                     {
1430                         Type paramType = paramTypes[i];
1431                         if (paramType.IsGenericParameter)
1432                             genericParams[i] = paramContracts[paramType.GenericParameterPosition];
1433                         else
1434                             genericParams[i] = paramType;
1435                     }
1436                 }
1437                 boundClassContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(stableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(this.UnderlyingType), genericParams)), stableName.Namespace);
1438                 if (BaseContract != null)
1439                     boundClassContract.BaseContract = (ClassDataContract)BaseContract.BindGenericParameters(paramContracts, boundContracts);
1440                 boundClassContract.IsISerializable = this.IsISerializable;
1441                 boundClassContract.IsValueType = this.IsValueType;
1442                 boundClassContract.IsReference = this.IsReference;
1443                 if (Members != null)
1444                 {
1445                     boundClassContract.Members = new List<DataMember>(Members.Count);
1446                     foreach (DataMember member in Members)
1447                         boundClassContract.Members.Add(member.BindGenericParameters(paramContracts, boundContracts));
1448                 }
1449                 return boundClassContract;
1450             }
1451         }
1452
1453         internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
1454         {
1455             if (IsEqualOrChecked(other, checkedContracts))
1456                 return true;
1457
1458             if (base.Equals(other, checkedContracts))
1459             {
1460                 ClassDataContract dataContract = other as ClassDataContract;
1461                 if (dataContract != null)
1462                 {
1463                     if (IsISerializable)
1464                     {
1465                         if (!dataContract.IsISerializable)
1466                             return false;
1467                     }
1468                     else
1469                     {
1470                         if (dataContract.IsISerializable)
1471                             return false;
1472
1473                         if (Members == null)
1474                         {
1475                             if (dataContract.Members != null)
1476                             {
1477                                 // check that all the datamembers in dataContract.Members are optional
1478                                 if (!IsEveryDataMemberOptional(dataContract.Members))
1479                                     return false;
1480                             }
1481                         }
1482                         else if (dataContract.Members == null)
1483                         {
1484                             // check that all the datamembers in Members are optional
1485                             if (!IsEveryDataMemberOptional(Members))
1486                                 return false;
1487                         }
1488                         else
1489                         {
1490                             Dictionary<string, DataMember> membersDictionary = new Dictionary<string, DataMember>(Members.Count);
1491                             List<DataMember> dataContractMembersList = new List<DataMember>();
1492                             for (int i = 0; i < Members.Count; i++)
1493                             {
1494                                 membersDictionary.Add(Members[i].Name, Members[i]);
1495                             }
1496
1497                             for (int i = 0; i < dataContract.Members.Count; i++)
1498                             {
1499                                 // check that all datamembers common to both datacontracts match
1500                                 DataMember dataMember;
1501                                 if (membersDictionary.TryGetValue(dataContract.Members[i].Name, out dataMember))
1502                                 {
1503                                     if (dataMember.Equals(dataContract.Members[i], checkedContracts))
1504                                     {
1505                                         membersDictionary.Remove(dataMember.Name);
1506                                     }
1507                                     else
1508                                     {
1509                                         return false;
1510                                     }
1511                                 }
1512                                 // otherwise save the non-matching datamembers for later verification 
1513                                 else
1514                                 {
1515                                     dataContractMembersList.Add(dataContract.Members[i]);
1516                                 }
1517                             }
1518
1519                             // check that datamembers left over from either datacontract are optional
1520                             if (!IsEveryDataMemberOptional(membersDictionary.Values))
1521                                 return false;
1522                             if (!IsEveryDataMemberOptional(dataContractMembersList))
1523                                 return false;
1524
1525                         }
1526                     }
1527
1528                     if (BaseContract == null)
1529                         return (dataContract.BaseContract == null);
1530                     else if (dataContract.BaseContract == null)
1531                         return false;
1532                     else
1533                         return BaseContract.Equals(dataContract.BaseContract, checkedContracts);
1534                 }
1535             }
1536             return false;
1537         }
1538
1539         bool IsEveryDataMemberOptional(IEnumerable<DataMember> dataMembers)
1540         {
1541             foreach (DataMember dataMember in dataMembers)
1542             {
1543                 if (dataMember.IsRequired)
1544                     return false;
1545             }
1546             return true;
1547         }
1548
1549         public override int GetHashCode()
1550         {
1551             return base.GetHashCode();
1552         }
1553
1554         internal class DataMemberComparer : IComparer<DataMember>
1555         {
1556             public int Compare(DataMember x, DataMember y)
1557             {
1558                 int orderCompare = x.Order - y.Order;
1559                 if (orderCompare != 0)
1560                     return orderCompare;
1561
1562                 return String.CompareOrdinal(x.Name, y.Name);
1563             }
1564
1565             internal static DataMemberComparer Singleton = new DataMemberComparer();
1566         }
1567     }
1568 }
1569