1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
4 namespace System.Runtime.Serialization
7 using System.Collections;
8 using System.Collections.Generic;
9 using System.Reflection;
10 using System.Security;
11 using System.Threading;
13 using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
16 public sealed class ClassDataContract : DataContract
18 internal sealed class ClassDataContract : DataContract
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;
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;
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;
42 [Fx.Tag.SecurityNote(Critical = "XmlDictionaryString representing the XML namespaces for members of class."
43 + "Statically cached and used from IL generated code.")]
45 XmlDictionaryString[] childElementNamespaces;
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.")]
50 ClassDataContractCriticalHelper helper;
52 [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'",
53 Safe = "Doesn't leak anything.")]
54 [SecuritySafeCritical]
55 internal ClassDataContract()
56 : base(new ClassDataContractCriticalHelper())
58 InitClassDataContract();
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))
67 InitClassDataContract();
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))
76 InitClassDataContract();
79 [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical fields; called from all constructors.")]
81 void InitClassDataContract()
83 this.helper = base.Helper as ClassDataContractCriticalHelper;
84 this.ContractNamespaces = helper.ContractNamespaces;
85 this.MemberNames = helper.MemberNames;
86 this.MemberNamespaces = helper.MemberNamespaces;
89 internal ClassDataContract BaseContract
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; }
96 [Fx.Tag.SecurityNote(Critical = "Sets the critical baseContract property.")]
98 set { helper.BaseContract = value; }
101 internal List<DataMember> Members
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; }
108 [Fx.Tag.SecurityNote(Critical = "Sets the critical members property.",
109 Safe = "Protected for write if contract has underlyingType.")]
111 set { helper.Members = value; }
114 public XmlDictionaryString[] ChildElementNamespaces
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]
121 if (this.childElementNamespaces == null)
125 if (this.childElementNamespaces == null)
127 if (helper.ChildElementNamespaces == null)
129 XmlDictionaryString[] tempChildElementamespaces = CreateChildElementNamespaces();
130 Thread.MemoryBarrier();
131 helper.ChildElementNamespaces = tempChildElementamespaces;
133 this.childElementNamespaces = helper.ChildElementNamespaces;
137 return this.childElementNamespaces;
141 internal MethodInfo OnSerializing
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; }
149 internal MethodInfo OnSerialized
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; }
157 internal MethodInfo OnDeserializing
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; }
165 internal MethodInfo OnDeserialized
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; }
173 internal MethodInfo ExtensionDataSetMethod
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; }
181 internal override DataContractDictionary KnownDataContracts
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; }
188 [Fx.Tag.SecurityNote(Critical = "Sets the critical knownDataContracts property.",
189 Safe = "Protected for write if contract has underlyingType.")]
191 set { helper.KnownDataContracts = value; }
194 internal override bool IsISerializable
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; }
201 [Fx.Tag.SecurityNote(Critical = "Sets the critical isISerializable property.",
202 Safe = "Protected for write if contract has underlyingType.")]
204 set { helper.IsISerializable = value; }
207 internal bool IsNonAttributedType
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; }
215 internal bool HasDataContract
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; }
223 internal bool HasExtensionData
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; }
231 internal string SerializationExceptionMessage
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; }
239 internal string DeserializationExceptionMessage
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; }
247 internal bool IsReadOnlyContract
249 get { return this.DeserializationExceptionMessage != null; }
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()
257 return helper.GetISerializableConstructor();
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()
265 return helper.GetNonAttributedTypeConstructor();
268 internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate
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]
275 if (helper.XmlFormatWriterDelegate == null)
279 if (helper.XmlFormatWriterDelegate == null)
281 XmlFormatClassWriterDelegate tempDelegate = new XmlFormatWriterGenerator().GenerateClassWriter(this);
282 Thread.MemoryBarrier();
283 helper.XmlFormatWriterDelegate = tempDelegate;
287 return helper.XmlFormatWriterDelegate;
291 internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate
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]
298 if (helper.XmlFormatReaderDelegate == null)
302 if (helper.XmlFormatReaderDelegate == null)
304 if (this.IsReadOnlyContract)
306 ThrowInvalidDataContractException(helper.DeserializationExceptionMessage, null /*type*/);
308 XmlFormatClassReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateClassReader(this);
309 Thread.MemoryBarrier();
310 helper.XmlFormatReaderDelegate = tempDelegate;
314 return helper.XmlFormatReaderDelegate;
318 internal static ClassDataContract CreateClassDataContractForKeyValue(Type type, XmlDictionaryString ns, string[] memberNames)
320 return new ClassDataContract(type, ns, memberNames);
323 internal static void CheckAndAddMember(List<DataMember> members, DataMember memberContract, Dictionary<string, DataMember> memberNamesTable)
325 DataMember existingMemberContract;
326 if (memberNamesTable.TryGetValue(memberContract.Name, out existingMemberContract))
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),
337 memberNamesTable.Add(memberContract.Name, memberContract);
338 members.Add(memberContract);
341 internal static XmlDictionaryString GetChildNamespaceToDeclare(DataContract dataContract, Type childType, XmlDictionary dictionary)
343 childType = DataContract.UnwrapNullableType(childType);
344 if (!childType.IsEnum && !Globals.TypeOfIXmlSerializable.IsAssignableFrom(childType)
345 && DataContract.GetBuiltInDataContract(childType) == null && childType != Globals.TypeOfDBNull)
347 string ns = DataContract.GetStableName(childType).Namespace;
348 if (ns.Length > 0 && ns != dataContract.Namespace.Value)
349 return dictionary.Add(ns);
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)
367 if (type.IsGenericParameter)
370 if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type))
376 if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false))
379 Type[] interfaceTypes = type.GetInterfaces();
380 foreach (Type interfaceType in interfaceTypes)
382 if (CollectionDataContract.IsCollectionInterface(interfaceType))
386 if (type.IsSerializable)
389 if (Globals.TypeOfISerializable.IsAssignableFrom(type))
392 if (type.IsDefined(Globals.TypeOfDataContractAttribute, false))
395 if (type == Globals.TypeOfExtensionDataObject)
398 if (type.IsValueType)
400 return type.IsVisible;
404 return (type.IsVisible &&
405 type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null) != null);
409 XmlDictionaryString[] CreateChildElementNamespaces()
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);
422 XmlDictionary dictionary = new XmlDictionary();
423 for (int i = 0; i < this.Members.Count; i++)
425 childElementNamespaces[i + baseChildElementNamespaceCount] = GetChildNamespaceToDeclare(this, this.Members[i].MemberType, dictionary);
428 return childElementNamespaces;
431 [Fx.Tag.SecurityNote(Critical = "Calls critical method on helper.",
432 Safe = "Doesn't leak anything.")]
433 [SecuritySafeCritical]
434 void EnsureMethodsImported()
436 helper.EnsureMethodsImported();
439 public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context)
441 XmlFormatWriterDelegate(xmlWriter, obj, context, this);
444 public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
447 object o = XmlFormatReaderDelegate(xmlReader, context, MemberNames, MemberNamespaces);
448 xmlReader.ReadEndElement();
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)
457 EnsureMethodsImported();
459 if (!IsTypeVisible(UnderlyingType))
461 if (securityException != null)
463 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
464 new SecurityException(SR.GetString(
465 SR.PartialTrustDataContractTypeNotPublic,
466 DataContract.GetClrTypeFullName(UnderlyingType)),
472 if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForRead(securityException))
475 if (ConstructorRequiresMemberAccess(GetISerializableConstructor()))
477 if (securityException != null)
479 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
480 new SecurityException(SR.GetString(
481 SR.PartialTrustISerializableNoPublicConstructor,
482 DataContract.GetClrTypeFullName(UnderlyingType)),
489 if (ConstructorRequiresMemberAccess(GetNonAttributedTypeConstructor()))
491 if (securityException != null)
493 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
494 new SecurityException(SR.GetString(
495 SR.PartialTrustNonAttributedSerializableTypeNoPublicConstructor,
496 DataContract.GetClrTypeFullName(UnderlyingType)),
503 if (MethodRequiresMemberAccess(this.OnDeserializing))
505 if (securityException != null)
507 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
508 new SecurityException(SR.GetString(
509 SR.PartialTrustDataContractOnDeserializingNotPublic,
510 DataContract.GetClrTypeFullName(UnderlyingType),
511 this.OnDeserializing.Name),
517 if (MethodRequiresMemberAccess(this.OnDeserialized))
519 if (securityException != null)
521 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
522 new SecurityException(SR.GetString(
523 SR.PartialTrustDataContractOnDeserializedNotPublic,
524 DataContract.GetClrTypeFullName(UnderlyingType),
525 this.OnDeserialized.Name),
531 if (this.Members != null)
533 for (int i = 0; i < this.Members.Count; i++)
535 if (this.Members[i].RequiresMemberAccessForSet())
537 if (securityException != null)
539 if (this.Members[i].MemberInfo is FieldInfo)
541 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
542 new SecurityException(SR.GetString(
543 SR.PartialTrustDataContractFieldSetNotPublic,
544 DataContract.GetClrTypeFullName(UnderlyingType),
545 this.Members[i].MemberInfo.Name),
550 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
551 new SecurityException(SR.GetString(
552 SR.PartialTrustDataContractPropertySetNotPublic,
553 DataContract.GetClrTypeFullName(UnderlyingType),
554 this.Members[i].MemberInfo.Name),
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)
575 EnsureMethodsImported();
577 if (!IsTypeVisible(UnderlyingType))
579 if (securityException != null)
581 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
582 new SecurityException(SR.GetString(
583 SR.PartialTrustDataContractTypeNotPublic,
584 DataContract.GetClrTypeFullName(UnderlyingType)),
590 if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForWrite(securityException))
593 if (MethodRequiresMemberAccess(this.OnSerializing))
595 if (securityException != null)
597 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
598 new SecurityException(SR.GetString(
599 SR.PartialTrustDataContractOnSerializingNotPublic,
600 DataContract.GetClrTypeFullName(this.UnderlyingType),
601 this.OnSerializing.Name),
607 if (MethodRequiresMemberAccess(this.OnSerialized))
609 if (securityException != null)
611 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
612 new SecurityException(SR.GetString(
613 SR.PartialTrustDataContractOnSerializedNotPublic,
614 DataContract.GetClrTypeFullName(UnderlyingType),
615 this.OnSerialized.Name),
621 if (this.Members != null)
623 for (int i = 0; i < this.Members.Count; i++)
625 if (this.Members[i].RequiresMemberAccessForGet())
627 if (securityException != null)
629 if (this.Members[i].MemberInfo is FieldInfo)
631 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
632 new SecurityException(SR.GetString(
633 SR.PartialTrustDataContractFieldGetNotPublic,
634 DataContract.GetClrTypeFullName(UnderlyingType),
635 this.Members[i].MemberInfo.Name),
640 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
641 new SecurityException(SR.GetString(
642 SR.PartialTrustDataContractPropertyGetNotPublic,
643 DataContract.GetClrTypeFullName(UnderlyingType),
644 this.Members[i].MemberInfo.Name),
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
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;
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;
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;
680 XmlDictionaryString[] childElementNamespaces;
681 XmlFormatClassReaderDelegate xmlFormatReaderDelegate;
682 XmlFormatClassWriterDelegate xmlFormatWriterDelegate;
684 public XmlDictionaryString[] ContractNamespaces;
685 public XmlDictionaryString[] MemberNames;
686 public XmlDictionaryString[] MemberNamespaces;
688 internal ClassDataContractCriticalHelper()
693 internal ClassDataContractCriticalHelper(Type type)
696 XmlQualifiedName stableName = GetStableNameAndSetHasDataContract(type);
697 if (type == Globals.TypeOfDBNull)
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();
708 Type baseType = type.BaseType;
709 this.isISerializable = (Globals.TypeOfISerializable.IsAssignableFrom(type));
710 SetIsNonAttributedType(type);
711 if (this.isISerializable)
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)))
718 this.IsValueType = type.IsValueType;
719 if (baseType != null && baseType != Globals.TypeOfObject && baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri)
721 DataContract baseContract = DataContract.GetDataContract(baseType);
722 if (baseContract is CollectionDataContract)
723 this.BaseContract = ((CollectionDataContract)baseContract).SharedTypeContract as ClassDataContract;
725 this.BaseContract = baseContract as ClassDataContract;
726 if (this.BaseContract != null && this.BaseContract.IsNonAttributedType && !this.isNonAttributedType)
728 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError
729 (new InvalidDataContractException(SR.GetString(SR.AttributedTypesCannotInheritFromNonAttributedSerializableTypes,
730 DataContract.GetClrTypeFullName(type), DataContract.GetClrTypeFullName(baseType))));
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);
742 this.StableName = stableName;
744 XmlDictionary dictionary = new XmlDictionary(2 + Members.Count);
745 Name = dictionary.Add(StableName.Name);
746 Namespace = dictionary.Add(StableName.Namespace);
748 int baseMemberCount = 0;
749 int baseContractCount = 0;
750 if (BaseContract == null)
752 MemberNames = new XmlDictionaryString[Members.Count];
753 MemberNamespaces = new XmlDictionaryString[Members.Count];
754 ContractNamespaces = new XmlDictionaryString[1];
758 if (BaseContract.IsReadOnlyContract)
760 this.serializationExceptionMessage = BaseContract.SerializationExceptionMessage;
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);
771 ContractNamespaces[baseContractCount] = Namespace;
772 for (int i = 0; i < Members.Count; i++)
774 MemberNames[i + baseMemberCount] = dictionary.Add(Members[i].Name);
775 MemberNamespaces[i + baseMemberCount] = Namespace;
778 EnsureMethodsImported();
781 internal ClassDataContractCriticalHelper(Type type, XmlDictionaryString ns, string[] memberNames)
784 this.StableName = new XmlQualifiedName(GetStableNameAndSetHasDataContract(type).Name, ns.Value);
786 XmlDictionary dictionary = new XmlDictionary(1 + Members.Count);
787 Name = dictionary.Add(StableName.Name);
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++)
794 Members[i].Name = memberNames[i];
795 MemberNames[i] = dictionary.Add(Members[i].Name);
796 MemberNamespaces[i] = Namespace;
798 EnsureMethodsImported();
801 void EnsureIsReferenceImported(Type type)
803 DataContractAttribute dataContractAttribute;
804 bool isReference = false;
805 bool hasDataContractAttribute = TryGetDCAttribute(type, out dataContractAttribute);
807 if (BaseContract != null)
809 if (hasDataContractAttribute && dataContractAttribute.IsReferenceSetExplicit)
811 bool baseIsReference = this.BaseContract.IsReference;
812 if ((baseIsReference && !dataContractAttribute.IsReference) ||
813 (!baseIsReference && dataContractAttribute.IsReference))
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),
825 isReference = dataContractAttribute.IsReference;
830 isReference = this.BaseContract.IsReference;
833 else if (hasDataContractAttribute)
835 if (dataContractAttribute.IsReference)
836 isReference = dataContractAttribute.IsReference;
839 if (isReference && type.IsValueType)
841 DataContract.ThrowInvalidDataContractException(
842 SR.GetString(SR.ValueTypeCannotHaveIsReference,
843 DataContract.GetClrTypeFullName(type),
850 this.IsReference = isReference;
853 void ImportDataMembers()
855 Type type = this.UnderlyingType;
856 EnsureIsReferenceImported(type);
857 List<DataMember> tempMembers = new List<DataMember>();
858 Dictionary<string, DataMember> memberNamesTable = new Dictionary<string, DataMember>();
860 MemberInfo[] memberInfos;
861 if (this.isNonAttributedType)
863 memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
867 memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
870 for (int i = 0; i < memberInfos.Length; i++)
872 MemberInfo member = memberInfos[i];
875 object[] memberAttributes = member.GetCustomAttributes(typeof(DataMemberAttribute), false);
876 if (memberAttributes != null && memberAttributes.Length > 0)
878 if (memberAttributes.Length > 1)
879 ThrowInvalidDataContractException(SR.GetString(SR.TooManyDataMembers, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name));
881 DataMember memberContract = new DataMember(member);
883 if (member.MemberType == MemberTypes.Property)
885 PropertyInfo property = (PropertyInfo)member;
887 MethodInfo getMethod = property.GetGetMethod(true);
888 if (getMethod != null && IsMethodOverriding(getMethod))
890 MethodInfo setMethod = property.GetSetMethod(true);
891 if (setMethod != null && IsMethodOverriding(setMethod))
893 if (getMethod == null)
894 ThrowInvalidDataContractException(SR.GetString(SR.NoGetMethodForProperty, property.DeclaringType, property.Name));
895 if (setMethod == null)
897 if (!SetIfGetOnlyCollection(memberContract, skipIfReadOnlyContract: false))
899 this.serializationExceptionMessage = SR.GetString(SR.NoSetMethodForProperty, property.DeclaringType, property.Name);
902 if (getMethod.GetParameters().Length > 0)
903 ThrowInvalidDataContractException(SR.GetString(SR.IndexedPropertyCannotBeSerialized, property.DeclaringType, property.Name));
905 else if (member.MemberType != MemberTypes.Field)
906 ThrowInvalidDataContractException(SR.GetString(SR.InvalidMember, DataContract.GetClrTypeFullName(type), member.Name));
908 DataMemberAttribute memberAttribute = (DataMemberAttribute)memberAttributes[0];
909 if (memberAttribute.IsNameSetExplicit)
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;
916 memberContract.Name = member.Name;
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)
923 ThrowInvalidDataContractException(
924 SR.GetString(SR.IsRequiredDataMemberOnIsReferenceDataContractType,
925 DataContract.GetClrTypeFullName(member.DeclaringType),
926 member.Name, true), type);
928 memberContract.EmitDefaultValue = memberAttribute.EmitDefaultValue;
929 memberContract.Order = memberAttribute.Order;
930 CheckAndAddMember(tempMembers, memberContract, memberNamesTable);
933 else if (this.isNonAttributedType)
935 FieldInfo field = member as FieldInfo;
936 PropertyInfo property = member as PropertyInfo;
937 if ((field == null && property == null) || (field != null && field.IsInitOnly))
940 object[] memberAttributes = member.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), false);
941 if (memberAttributes != null && memberAttributes.Length > 0)
943 if (memberAttributes.Length > 1)
944 ThrowInvalidDataContractException(SR.GetString(SR.TooManyIgnoreDataMemberAttributes, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name));
948 DataMember memberContract = new DataMember(member);
949 if (property != null)
951 MethodInfo getMethod = property.GetGetMethod();
952 if (getMethod == null || IsMethodOverriding(getMethod) || getMethod.GetParameters().Length > 0)
955 MethodInfo setMethod = property.GetSetMethod(true);
956 if (setMethod == null)
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))
964 if (!setMethod.IsPublic || IsMethodOverriding(setMethod))
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)
974 memberContract.Name = DataContract.EncodeLocalName(member.Name);
975 memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType);
976 CheckAndAddMember(tempMembers, memberContract, memberNamesTable);
980 FieldInfo field = member as FieldInfo;
981 if (field != null && !field.IsNotSerialized)
983 DataMember memberContract = new DataMember(member);
985 memberContract.Name = DataContract.EncodeLocalName(member.Name);
986 object[] optionalFields = field.GetCustomAttributes(Globals.TypeOfOptionalFieldAttribute, false);
987 if (optionalFields == null || optionalFields.Length == 0)
989 if (this.IsReference)
991 ThrowInvalidDataContractException(
992 SR.GetString(SR.NonOptionalFieldMemberOnIsReferenceSerializableType,
993 DataContract.GetClrTypeFullName(member.DeclaringType),
994 member.Name, true), type);
996 memberContract.IsRequired = true;
998 memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType);
999 CheckAndAddMember(tempMembers, memberContract, memberNamesTable);
1003 if (tempMembers.Count > 1)
1004 tempMembers.Sort(DataMemberComparer.Singleton);
1006 SetIfMembersHaveConflict(tempMembers);
1008 Thread.MemoryBarrier();
1009 members = tempMembers;
1012 bool SetIfGetOnlyCollection(DataMember memberContract, bool skipIfReadOnlyContract)
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)
1017 memberContract.IsGetOnlyCollection = true;
1023 void SetIfMembersHaveConflict(List<DataMember> members)
1025 if (BaseContract == null)
1028 int baseTypeIndex = 0;
1029 List<Member> membersInHierarchy = new List<Member>();
1030 foreach (DataMember member in members)
1032 membersInHierarchy.Add(new Member(member, this.StableName.Namespace, baseTypeIndex));
1034 ClassDataContract currContract = BaseContract;
1035 while (currContract != null)
1038 foreach (DataMember member in currContract.Members)
1040 membersInHierarchy.Add(new Member(member, currContract.StableName.Namespace, baseTypeIndex));
1042 currContract = currContract.BaseContract;
1045 IComparer<Member> comparer = DataMemberConflictComparer.Singleton;
1046 membersInHierarchy.Sort(comparer);
1048 for (int i = 0; i < membersInHierarchy.Count - 1; 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)
1057 membersInHierarchy[endIndex].member.ConflictingMember = membersInHierarchy[endIndex + 1].member;
1058 if (!hasConflictingType)
1060 if (membersInHierarchy[endIndex + 1].member.HasConflictingNameAndType)
1062 hasConflictingType = true;
1066 hasConflictingType = (membersInHierarchy[endIndex].member.MemberType != membersInHierarchy[endIndex + 1].member.MemberType);
1072 if (hasConflictingType)
1074 for (int j = startIndex; j <= endIndex; j++)
1076 membersInHierarchy[j].member.HasConflictingNameAndType = true;
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)
1089 return DataContract.GetStableName(type, out this.hasDataContract);
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)
1098 this.isNonAttributedType = !type.IsSerializable && !this.hasDataContract && IsNonAttributedTypeValidForSerialization(type);
1101 static bool IsMethodOverriding(MethodInfo method)
1103 return method.IsVirtual && ((method.Attributes & MethodAttributes.NewSlot) == 0);
1106 internal void EnsureMethodsImported()
1108 if (!isMethodChecked && UnderlyingType != null)
1112 if (!isMethodChecked)
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++)
1118 MethodInfo method = methods[i];
1119 Type prevAttributeType = null;
1120 ParameterInfo[] parameters = method.GetParameters();
1121 if (HasExtensionData && IsValidExtensionDataSetMethod(method, parameters))
1123 if (method.Name == Globals.ExtensionDataSetExplicitMethod || !method.IsPublic)
1124 extensionDataSetMethod = XmlFormatGeneratorStatics.ExtensionDataSetExplicitMethodInfo;
1126 extensionDataSetMethod = method;
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;
1137 Thread.MemoryBarrier();
1138 isMethodChecked = true;
1144 bool IsValidExtensionDataSetMethod(MethodInfo method, ParameterInfo[] parameters)
1146 if (method.Name == Globals.ExtensionDataSetExplicitMethod || method.Name == Globals.ExtensionDataSetMethod)
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);
1159 static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo currentCallback, ref Type prevAttributeType)
1161 if (method.IsDefined(attributeType, false))
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);
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);
1176 prevAttributeType = attributeType;
1183 internal ClassDataContract BaseContract
1185 get { return baseContract; }
1188 baseContract = value;
1189 if (baseContract != null && IsValueType)
1190 ThrowInvalidDataContractException(SR.GetString(SR.ValueTypeCannotHaveBaseType, StableName.Name, StableName.Namespace, baseContract.StableName.Name, baseContract.StableName.Namespace));
1194 internal List<DataMember> Members
1196 get { return members; }
1197 set { members = value; }
1200 internal MethodInfo OnSerializing
1204 EnsureMethodsImported();
1205 return onSerializing;
1209 internal MethodInfo OnSerialized
1213 EnsureMethodsImported();
1214 return onSerialized;
1218 internal MethodInfo OnDeserializing
1222 EnsureMethodsImported();
1223 return onDeserializing;
1227 internal MethodInfo OnDeserialized
1231 EnsureMethodsImported();
1232 return onDeserialized;
1236 internal MethodInfo ExtensionDataSetMethod
1240 EnsureMethodsImported();
1241 return extensionDataSetMethod;
1245 internal override DataContractDictionary KnownDataContracts
1249 if (!isKnownTypeAttributeChecked && UnderlyingType != null)
1253 if (!isKnownTypeAttributeChecked)
1255 knownDataContracts = DataContract.ImportKnownTypeAttributes(this.UnderlyingType);
1256 Thread.MemoryBarrier();
1257 isKnownTypeAttributeChecked = true;
1261 return knownDataContracts;
1263 set { knownDataContracts = value; }
1266 internal string SerializationExceptionMessage
1268 get { return serializationExceptionMessage; }
1271 internal string DeserializationExceptionMessage
1275 if (serializationExceptionMessage == null)
1281 return SR.GetString(SR.ReadOnlyClassDeserialization, this.serializationExceptionMessage);
1286 internal override bool IsISerializable
1288 get { return isISerializable; }
1289 set { isISerializable = value; }
1292 internal bool HasDataContract
1294 get { return hasDataContract; }
1297 internal bool HasExtensionData
1299 get { return hasExtensionData; }
1302 internal bool IsNonAttributedType
1304 get { return isNonAttributedType; }
1307 internal ConstructorInfo GetISerializableConstructor()
1309 if (!IsISerializable)
1312 ConstructorInfo ctor = UnderlyingType.GetConstructor(Globals.ScanAllMembers, null, SerInfoCtorArgs, null);
1314 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.SerializationInfo_ConstructorNotFound, DataContract.GetClrTypeFullName(UnderlyingType))));
1319 internal ConstructorInfo GetNonAttributedTypeConstructor()
1321 if (!this.IsNonAttributedType)
1324 Type type = UnderlyingType;
1326 if (type.IsValueType)
1329 ConstructorInfo ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
1331 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.NonAttributedSerializableTypesMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type))));
1336 internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate
1338 get { return xmlFormatWriterDelegate; }
1339 set { xmlFormatWriterDelegate = value; }
1342 internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate
1344 get { return xmlFormatReaderDelegate; }
1345 set { xmlFormatReaderDelegate = value; }
1348 public XmlDictionaryString[] ChildElementNamespaces
1350 get { return childElementNamespaces; }
1351 set { childElementNamespaces = value; }
1354 static Type[] serInfoCtorArgs;
1355 static Type[] SerInfoCtorArgs
1359 if (serInfoCtorArgs == null)
1360 serInfoCtorArgs = new Type[] { typeof(SerializationInfo), typeof(StreamingContext) };
1361 return serInfoCtorArgs;
1365 internal struct Member
1367 internal Member(DataMember member, string ns, int baseTypeIndex)
1369 this.member = member;
1371 this.baseTypeIndex = baseTypeIndex;
1373 internal DataMember member;
1375 internal int baseTypeIndex;
1378 internal class DataMemberConflictComparer : IComparer<Member>
1380 public int Compare(Member x, Member y)
1382 int nsCompare = String.CompareOrdinal(x.ns, y.ns);
1386 int nameCompare = String.CompareOrdinal(x.member.Name, y.member.Name);
1387 if (nameCompare != 0)
1390 return x.baseTypeIndex - y.baseTypeIndex;
1393 internal static DataMemberConflictComparer Singleton = new DataMemberConflictComparer();
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)
1403 Type type = UnderlyingType;
1404 if (!type.IsGenericType || !type.ContainsGenericParameters)
1409 DataContract boundContract;
1410 if (boundContracts.TryGetValue(this, out boundContract))
1411 return boundContract;
1413 ClassDataContract boundClassContract = new ClassDataContract();
1414 boundContracts.Add(this, boundClassContract);
1415 XmlQualifiedName stableName;
1416 object[] genericParams;
1417 if (type.IsGenericTypeDefinition)
1419 stableName = this.StableName;
1420 genericParams = paramContracts;
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++)
1430 Type paramType = paramTypes[i];
1431 if (paramType.IsGenericParameter)
1432 genericParams[i] = paramContracts[paramType.GenericParameterPosition];
1434 genericParams[i] = paramType;
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)
1445 boundClassContract.Members = new List<DataMember>(Members.Count);
1446 foreach (DataMember member in Members)
1447 boundClassContract.Members.Add(member.BindGenericParameters(paramContracts, boundContracts));
1449 return boundClassContract;
1453 internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
1455 if (IsEqualOrChecked(other, checkedContracts))
1458 if (base.Equals(other, checkedContracts))
1460 ClassDataContract dataContract = other as ClassDataContract;
1461 if (dataContract != null)
1463 if (IsISerializable)
1465 if (!dataContract.IsISerializable)
1470 if (dataContract.IsISerializable)
1473 if (Members == null)
1475 if (dataContract.Members != null)
1477 // check that all the datamembers in dataContract.Members are optional
1478 if (!IsEveryDataMemberOptional(dataContract.Members))
1482 else if (dataContract.Members == null)
1484 // check that all the datamembers in Members are optional
1485 if (!IsEveryDataMemberOptional(Members))
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++)
1494 membersDictionary.Add(Members[i].Name, Members[i]);
1497 for (int i = 0; i < dataContract.Members.Count; i++)
1499 // check that all datamembers common to both datacontracts match
1500 DataMember dataMember;
1501 if (membersDictionary.TryGetValue(dataContract.Members[i].Name, out dataMember))
1503 if (dataMember.Equals(dataContract.Members[i], checkedContracts))
1505 membersDictionary.Remove(dataMember.Name);
1512 // otherwise save the non-matching datamembers for later verification
1515 dataContractMembersList.Add(dataContract.Members[i]);
1519 // check that datamembers left over from either datacontract are optional
1520 if (!IsEveryDataMemberOptional(membersDictionary.Values))
1522 if (!IsEveryDataMemberOptional(dataContractMembersList))
1528 if (BaseContract == null)
1529 return (dataContract.BaseContract == null);
1530 else if (dataContract.BaseContract == null)
1533 return BaseContract.Equals(dataContract.BaseContract, checkedContracts);
1539 bool IsEveryDataMemberOptional(IEnumerable<DataMember> dataMembers)
1541 foreach (DataMember dataMember in dataMembers)
1543 if (dataMember.IsRequired)
1549 public override int GetHashCode()
1551 return base.GetHashCode();
1554 internal class DataMemberComparer : IComparer<DataMember>
1556 public int Compare(DataMember x, DataMember y)
1558 int orderCompare = x.Order - y.Order;
1559 if (orderCompare != 0)
1560 return orderCompare;
1562 return String.CompareOrdinal(x.Name, y.Name);
1565 internal static DataMemberComparer Singleton = new DataMemberComparer();