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