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.")]
44 #if !NO_SECURITY_ATTRIBUTES
47 XmlDictionaryString[] childElementNamespaces;
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
54 ClassDataContractCriticalHelper helper;
56 [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'",
57 Safe = "Doesn't leak anything.")]
58 [SecuritySafeCritical]
59 internal ClassDataContract()
60 : base(new ClassDataContractCriticalHelper())
62 InitClassDataContract();
65 [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'",
66 Safe = "Doesn't leak anything.")]
67 #if !NO_SECURITY_ATTRIBUTES
68 [SecuritySafeCritical]
70 internal ClassDataContract(Type type)
71 : base(new ClassDataContractCriticalHelper(type))
73 InitClassDataContract();
76 [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'",
77 Safe = "Doesn't leak anything.")]
78 #if !NO_SECURITY_ATTRIBUTES
79 [SecuritySafeCritical]
81 ClassDataContract(Type type, XmlDictionaryString ns, string[] memberNames)
82 : base(new ClassDataContractCriticalHelper(type, ns, memberNames))
84 InitClassDataContract();
87 [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical fields; called from all constructors.")]
88 #if !NO_SECURITY_ATTRIBUTES
91 void InitClassDataContract()
93 this.helper = base.Helper as ClassDataContractCriticalHelper;
94 this.ContractNamespaces = helper.ContractNamespaces;
95 this.MemberNames = helper.MemberNames;
96 this.MemberNamespaces = helper.MemberNamespaces;
99 internal ClassDataContract BaseContract
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; }
106 [Fx.Tag.SecurityNote(Critical = "Sets the critical baseContract property.")]
108 set { helper.BaseContract = value; }
111 internal List<DataMember> Members
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; }
118 [Fx.Tag.SecurityNote(Critical = "Sets the critical members property.",
119 Safe = "Protected for write if contract has underlyingType.")]
121 set { helper.Members = value; }
124 public XmlDictionaryString[] ChildElementNamespaces
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]
131 if (this.childElementNamespaces == null)
135 if (this.childElementNamespaces == null)
137 if (helper.ChildElementNamespaces == null)
139 XmlDictionaryString[] tempChildElementamespaces = CreateChildElementNamespaces();
140 Thread.MemoryBarrier();
141 helper.ChildElementNamespaces = tempChildElementamespaces;
143 this.childElementNamespaces = helper.ChildElementNamespaces;
147 return this.childElementNamespaces;
151 internal MethodInfo OnSerializing
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; }
159 internal MethodInfo OnSerialized
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; }
167 internal MethodInfo OnDeserializing
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; }
175 internal MethodInfo OnDeserialized
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; }
183 internal MethodInfo ExtensionDataSetMethod
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; }
191 internal override DataContractDictionary KnownDataContracts
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; }
198 [Fx.Tag.SecurityNote(Critical = "Sets the critical knownDataContracts property.",
199 Safe = "Protected for write if contract has underlyingType.")]
201 set { helper.KnownDataContracts = value; }
204 internal override bool IsISerializable
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; }
211 [Fx.Tag.SecurityNote(Critical = "Sets the critical isISerializable property.",
212 Safe = "Protected for write if contract has underlyingType.")]
214 set { helper.IsISerializable = value; }
217 internal bool IsNonAttributedType
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; }
225 internal bool HasDataContract
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; }
233 internal bool HasExtensionData
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; }
241 internal string SerializationExceptionMessage
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; }
249 internal string DeserializationExceptionMessage
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; }
257 internal bool IsReadOnlyContract
259 get { return this.DeserializationExceptionMessage != null; }
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()
267 return helper.GetISerializableConstructor();
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()
275 return helper.GetNonAttributedTypeConstructor();
278 internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate
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]
285 if (helper.XmlFormatWriterDelegate == null)
289 if (helper.XmlFormatWriterDelegate == null)
291 XmlFormatClassWriterDelegate tempDelegate = new XmlFormatWriterGenerator().GenerateClassWriter(this);
292 Thread.MemoryBarrier();
293 helper.XmlFormatWriterDelegate = tempDelegate;
297 return helper.XmlFormatWriterDelegate;
301 internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate
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]
308 if (helper.XmlFormatReaderDelegate == null)
312 if (helper.XmlFormatReaderDelegate == null)
314 if (this.IsReadOnlyContract)
316 ThrowInvalidDataContractException(helper.DeserializationExceptionMessage, null /*type*/);
318 XmlFormatClassReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateClassReader(this);
319 Thread.MemoryBarrier();
320 helper.XmlFormatReaderDelegate = tempDelegate;
324 return helper.XmlFormatReaderDelegate;
328 internal static ClassDataContract CreateClassDataContractForKeyValue(Type type, XmlDictionaryString ns, string[] memberNames)
330 return new ClassDataContract(type, ns, memberNames);
333 internal static void CheckAndAddMember(List<DataMember> members, DataMember memberContract, Dictionary<string, DataMember> memberNamesTable)
335 DataMember existingMemberContract;
336 if (memberNamesTable.TryGetValue(memberContract.Name, out existingMemberContract))
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),
347 memberNamesTable.Add(memberContract.Name, memberContract);
348 members.Add(memberContract);
351 internal static XmlDictionaryString GetChildNamespaceToDeclare(DataContract dataContract, Type childType, XmlDictionary dictionary)
353 childType = DataContract.UnwrapNullableType(childType);
354 if (!childType.IsEnum && !Globals.TypeOfIXmlSerializable.IsAssignableFrom(childType)
355 && DataContract.GetBuiltInDataContract(childType) == null && childType != Globals.TypeOfDBNull)
357 string ns = DataContract.GetStableName(childType).Namespace;
358 if (ns.Length > 0 && ns != dataContract.Namespace.Value)
359 return dictionary.Add(ns);
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)
377 if (type.IsGenericParameter)
380 if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type))
386 if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false))
389 Type[] interfaceTypes = type.GetInterfaces();
390 foreach (Type interfaceType in interfaceTypes)
392 if (CollectionDataContract.IsCollectionInterface(interfaceType))
396 if (type.IsSerializable)
399 if (Globals.TypeOfISerializable.IsAssignableFrom(type))
402 if (type.IsDefined(Globals.TypeOfDataContractAttribute, false))
405 if (type == Globals.TypeOfExtensionDataObject)
408 if (type.IsValueType)
410 return type.IsVisible;
414 return (type.IsVisible &&
415 type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null) != null);
419 XmlDictionaryString[] CreateChildElementNamespaces()
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);
432 XmlDictionary dictionary = new XmlDictionary();
433 for (int i = 0; i < this.Members.Count; i++)
435 childElementNamespaces[i + baseChildElementNamespaceCount] = GetChildNamespaceToDeclare(this, this.Members[i].MemberType, dictionary);
438 return childElementNamespaces;
441 [Fx.Tag.SecurityNote(Critical = "Calls critical method on helper.",
442 Safe = "Doesn't leak anything.")]
443 [SecuritySafeCritical]
444 void EnsureMethodsImported()
446 helper.EnsureMethodsImported();
449 public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context)
451 XmlFormatWriterDelegate(xmlWriter, obj, context, this);
454 public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
457 object o = XmlFormatReaderDelegate(xmlReader, context, MemberNames, MemberNamespaces);
458 xmlReader.ReadEndElement();
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)
468 EnsureMethodsImported();
470 if (!IsTypeVisible(UnderlyingType))
472 if (securityException != null)
474 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
475 new SecurityException(SR.GetString(
476 SR.PartialTrustDataContractTypeNotPublic,
477 DataContract.GetClrTypeFullName(UnderlyingType)),
483 if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForRead(securityException))
486 if (ConstructorRequiresMemberAccess(GetISerializableConstructor()))
488 if (securityException != null)
490 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
491 new SecurityException(SR.GetString(
492 SR.PartialTrustISerializableNoPublicConstructor,
493 DataContract.GetClrTypeFullName(UnderlyingType)),
500 if (ConstructorRequiresMemberAccess(GetNonAttributedTypeConstructor()))
502 if (securityException != null)
504 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
505 new SecurityException(SR.GetString(
506 SR.PartialTrustNonAttributedSerializableTypeNoPublicConstructor,
507 DataContract.GetClrTypeFullName(UnderlyingType)),
514 if (MethodRequiresMemberAccess(this.OnDeserializing))
516 if (securityException != null)
518 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
519 new SecurityException(SR.GetString(
520 SR.PartialTrustDataContractOnDeserializingNotPublic,
521 DataContract.GetClrTypeFullName(UnderlyingType),
522 this.OnDeserializing.Name),
528 if (MethodRequiresMemberAccess(this.OnDeserialized))
530 if (securityException != null)
532 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
533 new SecurityException(SR.GetString(
534 SR.PartialTrustDataContractOnDeserializedNotPublic,
535 DataContract.GetClrTypeFullName(UnderlyingType),
536 this.OnDeserialized.Name),
542 if (this.Members != null)
544 for (int i = 0; i < this.Members.Count; i++)
546 if (this.Members[i].RequiresMemberAccessForSet())
548 if (securityException != null)
550 if (this.Members[i].MemberInfo is FieldInfo)
552 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
553 new SecurityException(SR.GetString(
554 SR.PartialTrustDataContractFieldSetNotPublic,
555 DataContract.GetClrTypeFullName(UnderlyingType),
556 this.Members[i].MemberInfo.Name),
561 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
562 new SecurityException(SR.GetString(
563 SR.PartialTrustDataContractPropertySetNotPublic,
564 DataContract.GetClrTypeFullName(UnderlyingType),
565 this.Members[i].MemberInfo.Name),
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)
584 EnsureMethodsImported();
586 if (!IsTypeVisible(UnderlyingType))
588 if (securityException != null)
590 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
591 new SecurityException(SR.GetString(
592 SR.PartialTrustDataContractTypeNotPublic,
593 DataContract.GetClrTypeFullName(UnderlyingType)),
599 if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForWrite(securityException))
602 if (MethodRequiresMemberAccess(this.OnSerializing))
604 if (securityException != null)
606 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
607 new SecurityException(SR.GetString(
608 SR.PartialTrustDataContractOnSerializingNotPublic,
609 DataContract.GetClrTypeFullName(this.UnderlyingType),
610 this.OnSerializing.Name),
616 if (MethodRequiresMemberAccess(this.OnSerialized))
618 if (securityException != null)
620 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
621 new SecurityException(SR.GetString(
622 SR.PartialTrustDataContractOnSerializedNotPublic,
623 DataContract.GetClrTypeFullName(UnderlyingType),
624 this.OnSerialized.Name),
630 if (this.Members != null)
632 for (int i = 0; i < this.Members.Count; i++)
634 if (this.Members[i].RequiresMemberAccessForGet())
636 if (securityException != null)
638 if (this.Members[i].MemberInfo is FieldInfo)
640 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
641 new SecurityException(SR.GetString(
642 SR.PartialTrustDataContractFieldGetNotPublic,
643 DataContract.GetClrTypeFullName(UnderlyingType),
644 this.Members[i].MemberInfo.Name),
649 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
650 new SecurityException(SR.GetString(
651 SR.PartialTrustDataContractPropertyGetNotPublic,
652 DataContract.GetClrTypeFullName(UnderlyingType),
653 this.Members[i].MemberInfo.Name),
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)]
674 class ClassDataContractCriticalHelper : DataContract.DataContractCriticalHelper
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;
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;
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;
694 XmlDictionaryString[] childElementNamespaces;
695 XmlFormatClassReaderDelegate xmlFormatReaderDelegate;
696 XmlFormatClassWriterDelegate xmlFormatWriterDelegate;
698 public XmlDictionaryString[] ContractNamespaces;
699 public XmlDictionaryString[] MemberNames;
700 public XmlDictionaryString[] MemberNamespaces;
702 internal ClassDataContractCriticalHelper()
707 internal ClassDataContractCriticalHelper(Type type)
710 XmlQualifiedName stableName = GetStableNameAndSetHasDataContract(type);
711 if (type == Globals.TypeOfDBNull)
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();
722 Type baseType = type.BaseType;
723 this.isISerializable = (Globals.TypeOfISerializable.IsAssignableFrom(type));
724 SetIsNonAttributedType(type);
725 if (this.isISerializable)
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)))
732 this.IsValueType = type.IsValueType;
733 if (baseType != null && baseType != Globals.TypeOfObject && baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri)
735 DataContract baseContract = DataContract.GetDataContract(baseType);
736 if (baseContract is CollectionDataContract)
737 this.BaseContract = ((CollectionDataContract)baseContract).SharedTypeContract as ClassDataContract;
739 this.BaseContract = baseContract as ClassDataContract;
740 if (this.BaseContract != null && this.BaseContract.IsNonAttributedType && !this.isNonAttributedType)
742 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError
743 (new InvalidDataContractException(SR.GetString(SR.AttributedTypesCannotInheritFromNonAttributedSerializableTypes,
744 DataContract.GetClrTypeFullName(type), DataContract.GetClrTypeFullName(baseType))));
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);
756 this.StableName = stableName;
758 XmlDictionary dictionary = new XmlDictionary(2 + Members.Count);
759 Name = dictionary.Add(StableName.Name);
760 Namespace = dictionary.Add(StableName.Namespace);
762 int baseMemberCount = 0;
763 int baseContractCount = 0;
764 if (BaseContract == null)
766 MemberNames = new XmlDictionaryString[Members.Count];
767 MemberNamespaces = new XmlDictionaryString[Members.Count];
768 ContractNamespaces = new XmlDictionaryString[1];
772 if (BaseContract.IsReadOnlyContract)
774 this.serializationExceptionMessage = BaseContract.SerializationExceptionMessage;
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);
785 ContractNamespaces[baseContractCount] = Namespace;
786 for (int i = 0; i < Members.Count; i++)
788 MemberNames[i + baseMemberCount] = dictionary.Add(Members[i].Name);
789 MemberNamespaces[i + baseMemberCount] = Namespace;
792 EnsureMethodsImported();
795 internal ClassDataContractCriticalHelper(Type type, XmlDictionaryString ns, string[] memberNames)
798 this.StableName = new XmlQualifiedName(GetStableNameAndSetHasDataContract(type).Name, ns.Value);
800 XmlDictionary dictionary = new XmlDictionary(1 + Members.Count);
801 Name = dictionary.Add(StableName.Name);
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++)
808 Members[i].Name = memberNames[i];
809 MemberNames[i] = dictionary.Add(Members[i].Name);
810 MemberNamespaces[i] = Namespace;
812 EnsureMethodsImported();
815 void EnsureIsReferenceImported(Type type)
817 DataContractAttribute dataContractAttribute;
818 bool isReference = false;
819 bool hasDataContractAttribute = TryGetDCAttribute(type, out dataContractAttribute);
821 if (BaseContract != null)
823 if (hasDataContractAttribute && dataContractAttribute.IsReferenceSetExplicitly)
825 bool baseIsReference = this.BaseContract.IsReference;
826 if ((baseIsReference && !dataContractAttribute.IsReference) ||
827 (!baseIsReference && dataContractAttribute.IsReference))
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),
839 isReference = dataContractAttribute.IsReference;
844 isReference = this.BaseContract.IsReference;
847 else if (hasDataContractAttribute)
849 if (dataContractAttribute.IsReference)
850 isReference = dataContractAttribute.IsReference;
853 if (isReference && type.IsValueType)
855 DataContract.ThrowInvalidDataContractException(
856 SR.GetString(SR.ValueTypeCannotHaveIsReference,
857 DataContract.GetClrTypeFullName(type),
864 this.IsReference = isReference;
867 void ImportDataMembers()
869 Type type = this.UnderlyingType;
870 EnsureIsReferenceImported(type);
871 List<DataMember> tempMembers = new List<DataMember>();
872 Dictionary<string, DataMember> memberNamesTable = new Dictionary<string, DataMember>();
874 MemberInfo[] memberInfos;
875 if (this.isNonAttributedType)
877 memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
881 memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
884 for (int i = 0; i < memberInfos.Length; i++)
886 MemberInfo member = memberInfos[i];
889 object[] memberAttributes = member.GetCustomAttributes(typeof(DataMemberAttribute), false);
890 if (memberAttributes != null && memberAttributes.Length > 0)
892 if (memberAttributes.Length > 1)
893 ThrowInvalidDataContractException(SR.GetString(SR.TooManyDataMembers, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name));
895 DataMember memberContract = new DataMember(member);
897 if (member.MemberType == MemberTypes.Property)
899 PropertyInfo property = (PropertyInfo)member;
901 MethodInfo getMethod = property.GetGetMethod(true);
902 if (getMethod != null && IsMethodOverriding(getMethod))
904 MethodInfo setMethod = property.GetSetMethod(true);
905 if (setMethod != null && IsMethodOverriding(setMethod))
907 if (getMethod == null)
908 ThrowInvalidDataContractException(SR.GetString(SR.NoGetMethodForProperty, property.DeclaringType, property.Name));
909 if (setMethod == null)
911 if (!SetIfGetOnlyCollection(memberContract, skipIfReadOnlyContract: false))
913 this.serializationExceptionMessage = SR.GetString(SR.NoSetMethodForProperty, property.DeclaringType, property.Name);
916 if (getMethod.GetParameters().Length > 0)
917 ThrowInvalidDataContractException(SR.GetString(SR.IndexedPropertyCannotBeSerialized, property.DeclaringType, property.Name));
919 else if (member.MemberType != MemberTypes.Field)
920 ThrowInvalidDataContractException(SR.GetString(SR.InvalidMember, DataContract.GetClrTypeFullName(type), member.Name));
922 DataMemberAttribute memberAttribute = (DataMemberAttribute)memberAttributes[0];
923 if (memberAttribute.IsNameSetExplicitly)
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;
930 memberContract.Name = member.Name;
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)
937 ThrowInvalidDataContractException(
938 SR.GetString(SR.IsRequiredDataMemberOnIsReferenceDataContractType,
939 DataContract.GetClrTypeFullName(member.DeclaringType),
940 member.Name, true), type);
942 memberContract.EmitDefaultValue = memberAttribute.EmitDefaultValue;
943 memberContract.Order = memberAttribute.Order;
944 CheckAndAddMember(tempMembers, memberContract, memberNamesTable);
947 else if (this.isNonAttributedType)
949 FieldInfo field = member as FieldInfo;
950 PropertyInfo property = member as PropertyInfo;
951 if ((field == null && property == null) || (field != null && field.IsInitOnly))
954 object[] memberAttributes = member.GetCustomAttributes(typeof(IgnoreDataMemberAttribute), false);
955 if (memberAttributes != null && memberAttributes.Length > 0)
957 if (memberAttributes.Length > 1)
958 ThrowInvalidDataContractException(SR.GetString(SR.TooManyIgnoreDataMemberAttributes, DataContract.GetClrTypeFullName(member.DeclaringType), member.Name));
962 DataMember memberContract = new DataMember(member);
963 if (property != null)
965 MethodInfo getMethod = property.GetGetMethod();
966 if (getMethod == null || IsMethodOverriding(getMethod) || getMethod.GetParameters().Length > 0)
969 MethodInfo setMethod = property.GetSetMethod(true);
970 if (setMethod == null)
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))
978 if (!setMethod.IsPublic || IsMethodOverriding(setMethod))
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)
988 memberContract.Name = DataContract.EncodeLocalName(member.Name);
989 memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType);
990 CheckAndAddMember(tempMembers, memberContract, memberNamesTable);
994 FieldInfo field = member as FieldInfo;
995 if (field != null && !field.IsNotSerialized)
997 DataMember memberContract = new DataMember(member);
999 memberContract.Name = DataContract.EncodeLocalName(member.Name);
1000 object[] optionalFields = field.GetCustomAttributes(Globals.TypeOfOptionalFieldAttribute, false);
1001 if (optionalFields == null || optionalFields.Length == 0)
1003 if (this.IsReference)
1005 ThrowInvalidDataContractException(
1006 SR.GetString(SR.NonOptionalFieldMemberOnIsReferenceSerializableType,
1007 DataContract.GetClrTypeFullName(member.DeclaringType),
1008 member.Name, true), type);
1010 memberContract.IsRequired = true;
1012 memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType);
1013 CheckAndAddMember(tempMembers, memberContract, memberNamesTable);
1017 if (tempMembers.Count > 1)
1018 tempMembers.Sort(DataMemberComparer.Singleton);
1020 SetIfMembersHaveConflict(tempMembers);
1022 Thread.MemoryBarrier();
1023 members = tempMembers;
1026 bool SetIfGetOnlyCollection(DataMember memberContract, bool skipIfReadOnlyContract)
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)
1031 memberContract.IsGetOnlyCollection = true;
1037 void SetIfMembersHaveConflict(List<DataMember> members)
1039 if (BaseContract == null)
1042 int baseTypeIndex = 0;
1043 List<Member> membersInHierarchy = new List<Member>();
1044 foreach (DataMember member in members)
1046 membersInHierarchy.Add(new Member(member, this.StableName.Namespace, baseTypeIndex));
1048 ClassDataContract currContract = BaseContract;
1049 while (currContract != null)
1052 foreach (DataMember member in currContract.Members)
1054 membersInHierarchy.Add(new Member(member, currContract.StableName.Namespace, baseTypeIndex));
1056 currContract = currContract.BaseContract;
1059 IComparer<Member> comparer = DataMemberConflictComparer.Singleton;
1060 membersInHierarchy.Sort(comparer);
1062 for (int i = 0; i < membersInHierarchy.Count - 1; 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)
1071 membersInHierarchy[endIndex].member.ConflictingMember = membersInHierarchy[endIndex + 1].member;
1072 if (!hasConflictingType)
1074 if (membersInHierarchy[endIndex + 1].member.HasConflictingNameAndType)
1076 hasConflictingType = true;
1080 hasConflictingType = (membersInHierarchy[endIndex].member.MemberType != membersInHierarchy[endIndex + 1].member.MemberType);
1086 if (hasConflictingType)
1088 for (int j = startIndex; j <= endIndex; j++)
1090 membersInHierarchy[j].member.HasConflictingNameAndType = true;
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)
1103 return DataContract.GetStableName(type, out this.hasDataContract);
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)
1112 this.isNonAttributedType = !type.IsSerializable && !this.hasDataContract && IsNonAttributedTypeValidForSerialization(type);
1115 static bool IsMethodOverriding(MethodInfo method)
1117 return method.IsVirtual && ((method.Attributes & MethodAttributes.NewSlot) == 0);
1120 internal void EnsureMethodsImported()
1122 if (!isMethodChecked && UnderlyingType != null)
1126 if (!isMethodChecked)
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++)
1132 MethodInfo method = methods[i];
1133 Type prevAttributeType = null;
1134 ParameterInfo[] parameters = method.GetParameters();
1135 if (HasExtensionData && IsValidExtensionDataSetMethod(method, parameters))
1137 if (method.Name == Globals.ExtensionDataSetExplicitMethod || !method.IsPublic)
1138 extensionDataSetMethod = XmlFormatGeneratorStatics.ExtensionDataSetExplicitMethodInfo;
1140 extensionDataSetMethod = method;
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;
1151 Thread.MemoryBarrier();
1152 isMethodChecked = true;
1158 bool IsValidExtensionDataSetMethod(MethodInfo method, ParameterInfo[] parameters)
1160 if (method.Name == Globals.ExtensionDataSetExplicitMethod || method.Name == Globals.ExtensionDataSetMethod)
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);
1173 static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameters, Type attributeType, MethodInfo currentCallback, ref Type prevAttributeType)
1175 if (method.IsDefined(attributeType, false))
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);
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);
1190 prevAttributeType = attributeType;
1197 internal ClassDataContract BaseContract
1199 get { return baseContract; }
1202 baseContract = value;
1203 if (baseContract != null && IsValueType)
1204 ThrowInvalidDataContractException(SR.GetString(SR.ValueTypeCannotHaveBaseType, StableName.Name, StableName.Namespace, baseContract.StableName.Name, baseContract.StableName.Namespace));
1208 internal List<DataMember> Members
1210 get { return members; }
1211 set { members = value; }
1214 internal MethodInfo OnSerializing
1218 EnsureMethodsImported();
1219 return onSerializing;
1223 internal MethodInfo OnSerialized
1227 EnsureMethodsImported();
1228 return onSerialized;
1232 internal MethodInfo OnDeserializing
1236 EnsureMethodsImported();
1237 return onDeserializing;
1241 internal MethodInfo OnDeserialized
1245 EnsureMethodsImported();
1246 return onDeserialized;
1250 internal MethodInfo ExtensionDataSetMethod
1254 EnsureMethodsImported();
1255 return extensionDataSetMethod;
1259 internal override DataContractDictionary KnownDataContracts
1263 if (!isKnownTypeAttributeChecked && UnderlyingType != null)
1267 if (!isKnownTypeAttributeChecked)
1269 knownDataContracts = DataContract.ImportKnownTypeAttributes(this.UnderlyingType);
1270 Thread.MemoryBarrier();
1271 isKnownTypeAttributeChecked = true;
1275 return knownDataContracts;
1277 set { knownDataContracts = value; }
1280 internal string SerializationExceptionMessage
1282 get { return serializationExceptionMessage; }
1285 internal string DeserializationExceptionMessage
1289 if (serializationExceptionMessage == null)
1295 return SR.GetString(SR.ReadOnlyClassDeserialization, this.serializationExceptionMessage);
1300 internal override bool IsISerializable
1302 get { return isISerializable; }
1303 set { isISerializable = value; }
1306 internal bool HasDataContract
1308 get { return hasDataContract; }
1311 internal bool HasExtensionData
1313 get { return hasExtensionData; }
1316 internal bool IsNonAttributedType
1318 get { return isNonAttributedType; }
1321 internal ConstructorInfo GetISerializableConstructor()
1323 if (!IsISerializable)
1326 ConstructorInfo ctor = UnderlyingType.GetConstructor(Globals.ScanAllMembers, null, SerInfoCtorArgs, null);
1328 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.SerializationInfo_ConstructorNotFound, DataContract.GetClrTypeFullName(UnderlyingType))));
1333 internal ConstructorInfo GetNonAttributedTypeConstructor()
1335 if (!this.IsNonAttributedType)
1338 Type type = UnderlyingType;
1340 if (type.IsValueType)
1343 ConstructorInfo ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
1345 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.NonAttributedSerializableTypesMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type))));
1350 internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate
1352 get { return xmlFormatWriterDelegate; }
1353 set { xmlFormatWriterDelegate = value; }
1356 internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate
1358 get { return xmlFormatReaderDelegate; }
1359 set { xmlFormatReaderDelegate = value; }
1362 public XmlDictionaryString[] ChildElementNamespaces
1364 get { return childElementNamespaces; }
1365 set { childElementNamespaces = value; }
1368 static Type[] serInfoCtorArgs;
1369 static Type[] SerInfoCtorArgs
1373 if (serInfoCtorArgs == null)
1374 serInfoCtorArgs = new Type[] { typeof(SerializationInfo), typeof(StreamingContext) };
1375 return serInfoCtorArgs;
1379 internal struct Member
1381 internal Member(DataMember member, string ns, int baseTypeIndex)
1383 this.member = member;
1385 this.baseTypeIndex = baseTypeIndex;
1387 internal DataMember member;
1389 internal int baseTypeIndex;
1392 internal class DataMemberConflictComparer : IComparer<Member>
1394 public int Compare(Member x, Member y)
1396 int nsCompare = String.CompareOrdinal(x.ns, y.ns);
1400 int nameCompare = String.CompareOrdinal(x.member.Name, y.member.Name);
1401 if (nameCompare != 0)
1404 return x.baseTypeIndex - y.baseTypeIndex;
1407 internal static DataMemberConflictComparer Singleton = new DataMemberConflictComparer();
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)
1417 Type type = UnderlyingType;
1418 if (!type.IsGenericType || !type.ContainsGenericParameters)
1423 DataContract boundContract;
1424 if (boundContracts.TryGetValue(this, out boundContract))
1425 return boundContract;
1427 ClassDataContract boundClassContract = new ClassDataContract();
1428 boundContracts.Add(this, boundClassContract);
1429 XmlQualifiedName stableName;
1430 object[] genericParams;
1431 if (type.IsGenericTypeDefinition)
1433 stableName = this.StableName;
1434 genericParams = paramContracts;
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++)
1444 Type paramType = paramTypes[i];
1445 if (paramType.IsGenericParameter)
1446 genericParams[i] = paramContracts[paramType.GenericParameterPosition];
1448 genericParams[i] = paramType;
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)
1459 boundClassContract.Members = new List<DataMember>(Members.Count);
1460 foreach (DataMember member in Members)
1461 boundClassContract.Members.Add(member.BindGenericParameters(paramContracts, boundContracts));
1463 return boundClassContract;
1467 internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
1469 if (IsEqualOrChecked(other, checkedContracts))
1472 if (base.Equals(other, checkedContracts))
1474 ClassDataContract dataContract = other as ClassDataContract;
1475 if (dataContract != null)
1477 if (IsISerializable)
1479 if (!dataContract.IsISerializable)
1484 if (dataContract.IsISerializable)
1487 if (Members == null)
1489 if (dataContract.Members != null)
1491 // check that all the datamembers in dataContract.Members are optional
1492 if (!IsEveryDataMemberOptional(dataContract.Members))
1496 else if (dataContract.Members == null)
1498 // check that all the datamembers in Members are optional
1499 if (!IsEveryDataMemberOptional(Members))
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++)
1508 membersDictionary.Add(Members[i].Name, Members[i]);
1511 for (int i = 0; i < dataContract.Members.Count; i++)
1513 // check that all datamembers common to both datacontracts match
1514 DataMember dataMember;
1515 if (membersDictionary.TryGetValue(dataContract.Members[i].Name, out dataMember))
1517 if (dataMember.Equals(dataContract.Members[i], checkedContracts))
1519 membersDictionary.Remove(dataMember.Name);
1526 // otherwise save the non-matching datamembers for later verification
1529 dataContractMembersList.Add(dataContract.Members[i]);
1533 // check that datamembers left over from either datacontract are optional
1534 if (!IsEveryDataMemberOptional(membersDictionary.Values))
1536 if (!IsEveryDataMemberOptional(dataContractMembersList))
1542 if (BaseContract == null)
1543 return (dataContract.BaseContract == null);
1544 else if (dataContract.BaseContract == null)
1547 return BaseContract.Equals(dataContract.BaseContract, checkedContracts);
1553 bool IsEveryDataMemberOptional(IEnumerable<DataMember> dataMembers)
1555 foreach (DataMember dataMember in dataMembers)
1557 if (dataMember.IsRequired)
1563 public override int GetHashCode()
1565 return base.GetHashCode();
1568 internal class DataMemberComparer : IComparer<DataMember>
1570 public int Compare(DataMember x, DataMember y)
1572 int orderCompare = x.Order - y.Order;
1573 if (orderCompare != 0)
1574 return orderCompare;
1576 return String.CompareOrdinal(x.Name, y.Name);
1579 internal static DataMemberComparer Singleton = new DataMemberComparer();