2016-08-03 10:59:49 +00:00
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Runtime.Serialization
{
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Reflection ;
using System.Security ;
using System.Threading ;
using System.Xml ;
using DataContractDictionary = System . Collections . Generic . Dictionary < System . Xml . XmlQualifiedName , DataContract > ;
#if USE_REFEMIT
public sealed class ClassDataContract : DataContract
#else
internal sealed class ClassDataContract : DataContract
#endif
{
[ Fx . Tag . SecurityNote ( Miscellaneous =
"RequiresReview - XmlDictionaryString(s) representing the XML namespaces for class members."
+ "statically cached and used from IL generated code. should ideally be Critical."
+ "marked SecurityNode to be callable from transparent IL generated code."
+ "not changed to property to avoid regressing performance; any changes to initalization should be reviewed." ) ]
public XmlDictionaryString [ ] ContractNamespaces ;
[ Fx . Tag . SecurityNote ( Miscellaneous =
"RequiresReview - XmlDictionaryString(s) representing the XML element names for class members."
+ "statically cached and used from IL generated code. should ideally be Critical."
+ "marked SecurityNode to be callable from transparent IL generated code."
+ "not changed to property to avoid regressing performance; any changes to initalization should be reviewed." ) ]
public XmlDictionaryString [ ] MemberNames ;
[ Fx . Tag . SecurityNote ( Miscellaneous =
"RequiresReview - XmlDictionaryString(s) representing the XML namespaces for class members."
+ "statically cached and used from IL generated code. should ideally be Critical."
+ "marked SecurityNode to be callable from transparent IL generated code."
+ "not changed to property to avoid regressing performance; any changes to initalization should be reviewed." ) ]
public XmlDictionaryString [ ] MemberNamespaces ;
[ Fx . Tag . SecurityNote ( Critical = "XmlDictionaryString representing the XML namespaces for members of class."
+ "Statically cached and used from IL generated code." ) ]
#if ! NO_SECURITY_ATTRIBUTES
[SecurityCritical]
#endif
XmlDictionaryString [ ] childElementNamespaces ;
[ Fx . Tag . SecurityNote ( Critical = "Holds instance of CriticalHelper which keeps state that is cached statically for serialization. "
+ "Static fields are marked SecurityCritical or readonly to prevent data from being modified or leaked to other components in appdomain." ) ]
#if ! NO_SECURITY_ATTRIBUTES
[SecurityCritical]
#endif
ClassDataContractCriticalHelper helper ;
[ Fx . Tag . SecurityNote ( Critical = "Initializes SecurityCritical field 'helper'" ,
Safe = "Doesn't leak anything." ) ]
[SecuritySafeCritical]
internal ClassDataContract ( )
: base ( new ClassDataContractCriticalHelper ( ) )
{
InitClassDataContract ( ) ;
}
[ Fx . Tag . SecurityNote ( Critical = "Initializes SecurityCritical field 'helper'" ,
Safe = "Doesn't leak anything." ) ]
#if ! NO_SECURITY_ATTRIBUTES
[SecuritySafeCritical]
#endif
internal ClassDataContract ( Type type )
: base ( new ClassDataContractCriticalHelper ( type ) )
{
InitClassDataContract ( ) ;
}
[ Fx . Tag . SecurityNote ( Critical = "Initializes SecurityCritical field 'helper'" ,
Safe = "Doesn't leak anything." ) ]
#if ! NO_SECURITY_ATTRIBUTES
[SecuritySafeCritical]
#endif
ClassDataContract ( Type type , XmlDictionaryString ns , string [ ] memberNames )
: base ( new ClassDataContractCriticalHelper ( type , ns , memberNames ) )
{
InitClassDataContract ( ) ;
}
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical fields; called from all constructors.")]
#if ! NO_SECURITY_ATTRIBUTES
[SecurityCritical]
#endif
void InitClassDataContract ( )
{
this . helper = base . Helper as ClassDataContractCriticalHelper ;
this . ContractNamespaces = helper . ContractNamespaces ;
this . MemberNames = helper . MemberNames ;
this . MemberNamespaces = helper . MemberNamespaces ;
}
internal ClassDataContract BaseContract
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical baseContract property." ,
Safe = "baseContract only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . BaseContract ; }
[Fx.Tag.SecurityNote(Critical = "Sets the critical baseContract property.")]
[SecurityCritical]
set { helper . BaseContract = value ; }
}
internal List < DataMember > Members
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical members property." ,
Safe = "members only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . Members ; }
[ Fx . Tag . SecurityNote ( Critical = "Sets the critical members property." ,
Safe = "Protected for write if contract has underlyingType." ) ]
[SecurityCritical]
set { helper . Members = value ; }
}
public XmlDictionaryString [ ] ChildElementNamespaces
{
[ Fx . Tag . SecurityNote ( Critical = "Sets the critical childElementNamespaces property." ,
Safe = "childElementNamespaces only needs to be protected for write; initialized in getter if null." ) ]
[SecuritySafeCritical]
get
{
if ( this . childElementNamespaces = = null )
{
lock ( this )
{
if ( this . childElementNamespaces = = null )
{
if ( helper . ChildElementNamespaces = = null )
{
XmlDictionaryString [ ] tempChildElementamespaces = CreateChildElementNamespaces ( ) ;
Thread . MemoryBarrier ( ) ;
helper . ChildElementNamespaces = tempChildElementamespaces ;
}
this . childElementNamespaces = helper . ChildElementNamespaces ;
}
}
}
return this . childElementNamespaces ;
}
}
internal MethodInfo OnSerializing
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical onSerializing property." ,
Safe = "onSerializing only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . OnSerializing ; }
}
internal MethodInfo OnSerialized
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical onSerialized property." ,
Safe = "onSerialized only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . OnSerialized ; }
}
internal MethodInfo OnDeserializing
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical onDeserializing property." ,
Safe = "onDeserializing only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . OnDeserializing ; }
}
internal MethodInfo OnDeserialized
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical onDeserialized property." ,
Safe = "onDeserialized only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . OnDeserialized ; }
}
internal MethodInfo ExtensionDataSetMethod
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical extensionDataSetMethod property." ,
Safe = "extensionDataSetMethod only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . ExtensionDataSetMethod ; }
}
internal override DataContractDictionary KnownDataContracts
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical knownDataContracts property." ,
Safe = "knownDataContracts only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . KnownDataContracts ; }
[ Fx . Tag . SecurityNote ( Critical = "Sets the critical knownDataContracts property." ,
Safe = "Protected for write if contract has underlyingType." ) ]
[SecurityCritical]
set { helper . KnownDataContracts = value ; }
}
internal override bool IsISerializable
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical isISerializable property." ,
Safe = "isISerializable only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . IsISerializable ; }
[ Fx . Tag . SecurityNote ( Critical = "Sets the critical isISerializable property." ,
Safe = "Protected for write if contract has underlyingType." ) ]
[SecurityCritical]
set { helper . IsISerializable = value ; }
}
internal bool IsNonAttributedType
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical IsNonAttributedType property." ,
Safe = "IsNonAttributedType only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . IsNonAttributedType ; }
}
internal bool HasDataContract
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical hasDataContract property." ,
Safe = "hasDataContract only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . HasDataContract ; }
}
internal bool HasExtensionData
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical hasExtensionData property." ,
Safe = "hasExtensionData only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . HasExtensionData ; }
}
internal string SerializationExceptionMessage
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical serializationExceptionMessage property." ,
Safe = "serializationExceptionMessage only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . SerializationExceptionMessage ; }
}
internal string DeserializationExceptionMessage
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical deserializationExceptionMessage property." ,
Safe = "deserializationExceptionMessage only needs to be protected for write." ) ]
[SecuritySafeCritical]
get { return helper . DeserializationExceptionMessage ; }
}
internal bool IsReadOnlyContract
{
get { return this . DeserializationExceptionMessage ! = null ; }
}
[ Fx . Tag . SecurityNote ( Critical = "Fetches information about which constructor should be used to initialize ISerializable types." ,
Safe = "only needs to be protected for write." ) ]
[SecuritySafeCritical]
internal ConstructorInfo GetISerializableConstructor ( )
{
return helper . GetISerializableConstructor ( ) ;
}
[ Fx . Tag . SecurityNote ( Critical = "Fetches information about which constructor should be used to initialize non-attributed types that are valid for serialization." ,
Safe = "only needs to be protected for write." ) ]
[SecuritySafeCritical]
internal ConstructorInfo GetNonAttributedTypeConstructor ( )
{
return helper . GetNonAttributedTypeConstructor ( ) ;
}
internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical xmlFormatWriterDelegate property." ,
Safe = "xmlFormatWriterDelegate only needs to be protected for write; initialized in getter if null." ) ]
[SecuritySafeCritical]
get
{
if ( helper . XmlFormatWriterDelegate = = null )
{
lock ( this )
{
if ( helper . XmlFormatWriterDelegate = = null )
{
XmlFormatClassWriterDelegate tempDelegate = new XmlFormatWriterGenerator ( ) . GenerateClassWriter ( this ) ;
Thread . MemoryBarrier ( ) ;
helper . XmlFormatWriterDelegate = tempDelegate ;
}
}
}
return helper . XmlFormatWriterDelegate ;
}
}
internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate
{
[ Fx . Tag . SecurityNote ( Critical = "Fetches the critical xmlFormatReaderDelegate property." ,
Safe = "xmlFormatReaderDelegate only needs to be protected for write; initialized in getter if null." ) ]
[SecuritySafeCritical]
get
{
if ( helper . XmlFormatReaderDelegate = = null )
{
lock ( this )
{
if ( helper . XmlFormatReaderDelegate = = null )
{
if ( this . IsReadOnlyContract )
{
ThrowInvalidDataContractException ( helper . DeserializationExceptionMessage , null /*type*/ ) ;
}
XmlFormatClassReaderDelegate tempDelegate = new XmlFormatReaderGenerator ( ) . GenerateClassReader ( this ) ;
Thread . MemoryBarrier ( ) ;
helper . XmlFormatReaderDelegate = tempDelegate ;
}
}
}
return helper . XmlFormatReaderDelegate ;
}
}
internal static ClassDataContract CreateClassDataContractForKeyValue ( Type type , XmlDictionaryString ns , string [ ] memberNames )
{
return new ClassDataContract ( type , ns , memberNames ) ;
}
internal static void CheckAndAddMember ( List < DataMember > members , DataMember memberContract , Dictionary < string , DataMember > memberNamesTable )
{
DataMember existingMemberContract ;
if ( memberNamesTable . TryGetValue ( memberContract . Name , out existingMemberContract ) )
{
Type declaringType = memberContract . MemberInfo . DeclaringType ;
DataContract . ThrowInvalidDataContractException (
SR . GetString ( ( declaringType . IsEnum ? SR . DupEnumMemberValue : SR . DupMemberName ) ,
existingMemberContract . MemberInfo . Name ,
memberContract . MemberInfo . Name ,
DataContract . GetClrTypeFullName ( declaringType ) ,
memberContract . Name ) ,
declaringType ) ;
}
memberNamesTable . Add ( memberContract . Name , memberContract ) ;
members . Add ( memberContract ) ;
}
internal static XmlDictionaryString GetChildNamespaceToDeclare ( DataContract dataContract , Type childType , XmlDictionary dictionary )
{
childType = DataContract . UnwrapNullableType ( childType ) ;
if ( ! childType . IsEnum & & ! Globals . TypeOfIXmlSerializable . IsAssignableFrom ( childType )
& & DataContract . GetBuiltInDataContract ( childType ) = = null & & childType ! = Globals . TypeOfDBNull )
{
string ns = DataContract . GetStableName ( childType ) . Namespace ;
if ( ns . Length > 0 & & ns ! = dataContract . Namespace . Value )
return dictionary . Add ( ns ) ;
}
return null ;
}
[ Fx . Tag . SecurityNote ( Miscellaneous = "RequiresReview - callers may need to depend on isNonAttributedType for a security decision."
+ "isNonAttributedType must be calculated correctly."
+ "IsNonAttributedTypeValidForSerialization is used as part of the isNonAttributedType calculation and is therefore marked with SecurityNote." ,
Safe = "Does not let caller influence isNonAttributedType calculation; no harm in leaking value." ) ]
// check whether a corresponding update is required in DataContractCriticalHelper.CreateDataContract
static internal bool IsNonAttributedTypeValidForSerialization ( Type type )
{
if ( type . IsArray )
return false ;
if ( type . IsEnum )
return false ;
if ( type . IsGenericParameter )
return false ;
if ( Globals . TypeOfIXmlSerializable . IsAssignableFrom ( type ) )
return false ;
if ( type . IsPointer )
return false ;
if ( type . IsDefined ( Globals . TypeOfCollectionDataContractAttribute , false ) )
return false ;
Type [ ] interfaceTypes = type . GetInterfaces ( ) ;
foreach ( Type interfaceType in interfaceTypes )
{
if ( CollectionDataContract . IsCollectionInterface ( interfaceType ) )
return false ;
}
if ( type . IsSerializable )
return false ;
if ( Globals . TypeOfISerializable . IsAssignableFrom ( type ) )
return false ;
if ( type . IsDefined ( Globals . TypeOfDataContractAttribute , false ) )
return false ;
if ( type = = Globals . TypeOfExtensionDataObject )
return false ;
if ( type . IsValueType )
{
return type . IsVisible ;
}
else
{
return ( type . IsVisible & &
type . GetConstructor ( BindingFlags . Instance | BindingFlags . NonPublic | BindingFlags . Public , null , Globals . EmptyTypeArray , null ) ! = null ) ;
}
}
XmlDictionaryString [ ] CreateChildElementNamespaces ( )
{
if ( Members = = null )
return null ;
XmlDictionaryString [ ] baseChildElementNamespaces = null ;
if ( this . BaseContract ! = null )
baseChildElementNamespaces = this . BaseContract . ChildElementNamespaces ;
int baseChildElementNamespaceCount = ( baseChildElementNamespaces ! = null ) ? baseChildElementNamespaces . Length : 0 ;
XmlDictionaryString [ ] childElementNamespaces = new XmlDictionaryString [ Members . Count + baseChildElementNamespaceCount ] ;
if ( baseChildElementNamespaceCount > 0 )
Array . Copy ( baseChildElementNamespaces , 0 , childElementNamespaces , 0 , baseChildElementNamespaces . Length ) ;
XmlDictionary dictionary = new XmlDictionary ( ) ;
for ( int i = 0 ; i < this . Members . Count ; i + + )
{
childElementNamespaces [ i + baseChildElementNamespaceCount ] = GetChildNamespaceToDeclare ( this , this . Members [ i ] . MemberType , dictionary ) ;
}
return childElementNamespaces ;
}
[ Fx . Tag . SecurityNote ( Critical = "Calls critical method on helper." ,
Safe = "Doesn't leak anything." ) ]
[SecuritySafeCritical]
void EnsureMethodsImported ( )
{
helper . EnsureMethodsImported ( ) ;
}
public override void WriteXmlValue ( XmlWriterDelegator xmlWriter , object obj , XmlObjectSerializerWriteContext context )
{
XmlFormatWriterDelegate ( xmlWriter , obj , context , this ) ;
}
public override object ReadXmlValue ( XmlReaderDelegator xmlReader , XmlObjectSerializerReadContext context )
{
xmlReader . Read ( ) ;
object o = XmlFormatReaderDelegate ( xmlReader , context , MemberNames , MemberNamespaces ) ;
xmlReader . ReadEndElement ( ) ;
return o ;
}
#if ! NO_DYNAMIC_CODEGEN
[ Fx . Tag . SecurityNote ( Miscellaneous = "RequiresReview - calculates whether this class requires MemberAccessPermission for deserialization."
+ "Since this information is used to determine whether to give the generated code access "
+ "permissions to private members, any changes to the logic should be reviewed." ) ]
internal bool RequiresMemberAccessForRead ( SecurityException securityException )
{
EnsureMethodsImported ( ) ;
if ( ! IsTypeVisible ( UnderlyingType ) )
{
if ( securityException ! = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustDataContractTypeNotPublic ,
DataContract . GetClrTypeFullName ( UnderlyingType ) ) ,
securityException ) ) ;
}
return true ;
}
if ( this . BaseContract ! = null & & this . BaseContract . RequiresMemberAccessForRead ( securityException ) )
return true ;
if ( ConstructorRequiresMemberAccess ( GetISerializableConstructor ( ) ) )
{
if ( securityException ! = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustISerializableNoPublicConstructor ,
DataContract . GetClrTypeFullName ( UnderlyingType ) ) ,
securityException ) ) ;
}
return true ;
}
if ( ConstructorRequiresMemberAccess ( GetNonAttributedTypeConstructor ( ) ) )
{
if ( securityException ! = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustNonAttributedSerializableTypeNoPublicConstructor ,
DataContract . GetClrTypeFullName ( UnderlyingType ) ) ,
securityException ) ) ;
}
return true ;
}
if ( MethodRequiresMemberAccess ( this . OnDeserializing ) )
{
if ( securityException ! = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustDataContractOnDeserializingNotPublic ,
DataContract . GetClrTypeFullName ( UnderlyingType ) ,
this . OnDeserializing . Name ) ,
securityException ) ) ;
}
return true ;
}
if ( MethodRequiresMemberAccess ( this . OnDeserialized ) )
{
if ( securityException ! = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustDataContractOnDeserializedNotPublic ,
DataContract . GetClrTypeFullName ( UnderlyingType ) ,
this . OnDeserialized . Name ) ,
securityException ) ) ;
}
return true ;
}
if ( this . Members ! = null )
{
for ( int i = 0 ; i < this . Members . Count ; i + + )
{
if ( this . Members [ i ] . RequiresMemberAccessForSet ( ) )
{
if ( securityException ! = null )
{
if ( this . Members [ i ] . MemberInfo is FieldInfo )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustDataContractFieldSetNotPublic ,
DataContract . GetClrTypeFullName ( UnderlyingType ) ,
this . Members [ i ] . MemberInfo . Name ) ,
securityException ) ) ;
}
else
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustDataContractPropertySetNotPublic ,
DataContract . GetClrTypeFullName ( UnderlyingType ) ,
this . Members [ i ] . MemberInfo . Name ) ,
securityException ) ) ;
}
}
return true ;
}
}
}
return false ;
}
[ Fx . Tag . SecurityNote ( Miscellaneous = "RequiresReview - calculates whether this class requires MemberAccessPermission for serialization."
+ " Since this information is used to determine whether to give the generated code access"
+ " permissions to private members, any changes to the logic should be reviewed." ) ]
internal bool RequiresMemberAccessForWrite ( SecurityException securityException )
{
2017-04-10 11:41:01 +00:00
#if MONO_FEATURE_CAS
2016-08-03 10:59:49 +00:00
EnsureMethodsImported ( ) ;
if ( ! IsTypeVisible ( UnderlyingType ) )
{
if ( securityException ! = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustDataContractTypeNotPublic ,
DataContract . GetClrTypeFullName ( UnderlyingType ) ) ,
securityException ) ) ;
}
return true ;
}
if ( this . BaseContract ! = null & & this . BaseContract . RequiresMemberAccessForWrite ( securityException ) )
return true ;
if ( MethodRequiresMemberAccess ( this . OnSerializing ) )
{
if ( securityException ! = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustDataContractOnSerializingNotPublic ,
DataContract . GetClrTypeFullName ( this . UnderlyingType ) ,
this . OnSerializing . Name ) ,
securityException ) ) ;
}
return true ;
}
if ( MethodRequiresMemberAccess ( this . OnSerialized ) )
{
if ( securityException ! = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustDataContractOnSerializedNotPublic ,
DataContract . GetClrTypeFullName ( UnderlyingType ) ,
this . OnSerialized . Name ) ,
securityException ) ) ;
}
return true ;
}
if ( this . Members ! = null )
{
for ( int i = 0 ; i < this . Members . Count ; i + + )
{
if ( this . Members [ i ] . RequiresMemberAccessForGet ( ) )
{
if ( securityException ! = null )
{
if ( this . Members [ i ] . MemberInfo is FieldInfo )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustDataContractFieldGetNotPublic ,
DataContract . GetClrTypeFullName ( UnderlyingType ) ,
this . Members [ i ] . MemberInfo . Name ) ,
securityException ) ) ;
}
else
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError (
new SecurityException ( SR . GetString (
SR . PartialTrustDataContractPropertyGetNotPublic ,
DataContract . GetClrTypeFullName ( UnderlyingType ) ,
this . Members [ i ] . MemberInfo . Name ) ,
securityException ) ) ;
}
}
return true ;
}
}
}
return false ;
#else
return true ;
#endif
}
#endif
[ Fx . Tag . SecurityNote ( Critical = "Holds all state used for (de)serializing classes."
+ " Since the data is cached statically, we lock down access to it." ) ]
#if ! NO_SECURITY_ATTRIBUTES
[SecurityCritical(SecurityCriticalScope.Everything)]
#endif
class ClassDataContractCriticalHelper : DataContract . DataContractCriticalHelper
{
ClassDataContract baseContract ;
List < DataMember > members ;
MethodInfo onSerializing , onSerialized ;
MethodInfo onDeserializing , onDeserialized ;
MethodInfo extensionDataSetMethod ;
DataContractDictionary knownDataContracts ;
string serializationExceptionMessage ;
bool isISerializable ;
bool isKnownTypeAttributeChecked ;
bool isMethodChecked ;
bool hasExtensionData ;
[Fx.Tag.SecurityNote(Miscellaneous = "in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and hasDataContract.")]
bool isNonAttributedType ;
[Fx.Tag.SecurityNote(Miscellaneous = "in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and isNonAttributedType.")]
bool hasDataContract ;
XmlDictionaryString [ ] childElementNamespaces ;
XmlFormatClassReaderDelegate xmlFormatReaderDelegate ;
XmlFormatClassWriterDelegate xmlFormatWriterDelegate ;
public XmlDictionaryString [ ] ContractNamespaces ;
public XmlDictionaryString [ ] MemberNames ;
public XmlDictionaryString [ ] MemberNamespaces ;
internal ClassDataContractCriticalHelper ( )
: base ( )
{
}
internal ClassDataContractCriticalHelper ( Type type )
: base ( type )
{
XmlQualifiedName stableName = GetStableNameAndSetHasDataContract ( type ) ;
if ( type = = Globals . TypeOfDBNull )
{
this . StableName = stableName ;
this . members = new List < DataMember > ( ) ;
XmlDictionary dictionary = new XmlDictionary ( 2 ) ;
this . Name = dictionary . Add ( StableName . Name ) ;
this . Namespace = dictionary . Add ( StableName . Namespace ) ;
this . ContractNamespaces = this . MemberNames = this . MemberNamespaces = new XmlDictionaryString [ ] { } ;
EnsureMethodsImported ( ) ;
return ;
}
Type baseType = type . BaseType ;
this . isISerializable = ( Globals . TypeOfISerializable . IsAssignableFrom ( type ) ) ;
SetIsNonAttributedType ( type ) ;
if ( this . isISerializable )
{
if ( HasDataContract )
throw System . Runtime . Serialization . DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidDataContractException ( SR . GetString ( SR . ISerializableCannotHaveDataContract , DataContract . GetClrTypeFullName ( type ) ) ) ) ;
if ( baseType ! = null & & ! ( baseType . IsSerializable & & Globals . TypeOfISerializable . IsAssignableFrom ( baseType ) ) )
baseType = null ;
}
this . IsValueType = type . IsValueType ;
if ( baseType ! = null & & baseType ! = Globals . TypeOfObject & & baseType ! = Globals . TypeOfValueType & & baseType ! = Globals . TypeOfUri )
{
DataContract baseContract = DataContract . GetDataContract ( baseType ) ;
if ( baseContract is CollectionDataContract )
this . BaseContract = ( ( CollectionDataContract ) baseContract ) . SharedTypeContract as ClassDataContract ;
else
this . BaseContract = baseContract as ClassDataContract ;
if ( this . BaseContract ! = null & & this . BaseContract . IsNonAttributedType & & ! this . isNonAttributedType )
{
throw System . Runtime . Serialization . DiagnosticUtility . ExceptionUtility . ThrowHelperError
( new InvalidDataContractException ( SR . GetString ( SR . AttributedTypesCannotInheritFromNonAttributedSerializableTypes ,
DataContract . GetClrTypeFullName ( type ) , DataContract . GetClrTypeFullName ( baseType ) ) ) ) ;
}
}
else
this . BaseContract = null ;
hasExtensionData = ( Globals . TypeOfIExtensibleDataObject . IsAssignableFrom ( type ) ) ;
if ( hasExtensionData & & ! HasDataContract & & ! IsNonAttributedType )
throw System . Runtime . Serialization . DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidDataContractException ( SR . GetString ( SR . OnlyDataContractTypesCanHaveExtensionData , DataContract . GetClrTypeFullName ( type ) ) ) ) ;
if ( this . isISerializable )
SetDataContractName ( stableName ) ;
else
{
this . StableName = stableName ;
ImportDataMembers ( ) ;
XmlDictionary dictionary = new XmlDictionary ( 2 + Members . Count ) ;
Name = dictionary . Add ( StableName . Name ) ;
Namespace = dictionary . Add ( StableName . Namespace ) ;
int baseMemberCount = 0 ;
int baseContractCount = 0 ;
if ( BaseContract = = null )
{
MemberNames = new XmlDictionaryString [ Members . Count ] ;
MemberNamespaces = new XmlDictionaryString [ Members . Count ] ;
ContractNamespaces = new XmlDictionaryString [ 1 ] ;
}
else
{
if ( BaseContract . IsReadOnlyContract )
{
this . serializationExceptionMessage = BaseContract . SerializationExceptionMessage ;
}
baseMemberCount = BaseContract . MemberNames . Length ;
MemberNames = new XmlDictionaryString [ Members . Count + baseMemberCount ] ;
Array . Copy ( BaseContract . MemberNames , MemberNames , baseMemberCount ) ;
MemberNamespaces = new XmlDictionaryString [ Members . Count + baseMemberCount ] ;
Array . Copy ( BaseContract . MemberNamespaces , MemberNamespaces , baseMemberCount ) ;
baseContractCount = BaseContract . ContractNamespaces . Length ;
ContractNamespaces = new XmlDictionaryString [ 1 + baseContractCount ] ;
Array . Copy ( BaseContract . ContractNamespaces , ContractNamespaces , baseContractCount ) ;
}
ContractNamespaces [ baseContractCount ] = Namespace ;
for ( int i = 0 ; i < Members . Count ; i + + )
{
MemberNames [ i + baseMemberCount ] = dictionary . Add ( Members [ i ] . Name ) ;
MemberNamespaces [ i + baseMemberCount ] = Namespace ;
}
}
EnsureMethodsImported ( ) ;
}
internal ClassDataContractCriticalHelper ( Type type , XmlDictionaryString ns , string [ ] memberNames )
: base ( type )
{
this . StableName = new XmlQualifiedName ( GetStableNameAndSetHasDataContract ( type ) . Name , ns . Value ) ;
ImportDataMembers ( ) ;
XmlDictionary dictionary = new XmlDictionary ( 1 + Members . Count ) ;
Name = dictionary . Add ( StableName . Name ) ;
Namespace = ns ;
ContractNamespaces = new XmlDictionaryString [ ] { Namespace } ;
MemberNames = new XmlDictionaryString [ Members . Count ] ;
MemberNamespaces = new XmlDictionaryString [ Members . Count ] ;
for ( int i = 0 ; i < Members . Count ; i + + )
{
Members [ i ] . Name = memberNames [ i ] ;
MemberNames [ i ] = dictionary . Add ( Members [ i ] . Name ) ;
MemberNamespaces [ i ] = Namespace ;
}
EnsureMethodsImported ( ) ;
}
void EnsureIsReferenceImported ( Type type )
{
DataContractAttribute dataContractAttribute ;
bool isReference = false ;
bool hasDataContractAttribute = TryGetDCAttribute ( type , out dataContractAttribute ) ;
if ( BaseContract ! = null )
{
if ( hasDataContractAttribute & & dataContractAttribute . IsReferenceSetExplicitly )
{
bool baseIsReference = this . BaseContract . IsReference ;
if ( ( baseIsReference & & ! dataContractAttribute . IsReference ) | |
( ! baseIsReference & & dataContractAttribute . IsReference ) )
{
DataContract . ThrowInvalidDataContractException (
SR . GetString ( SR . InconsistentIsReference ,
DataContract . GetClrTypeFullName ( type ) ,
dataContractAttribute . IsReference ,
DataContract . GetClrTypeFullName ( this . BaseContract . UnderlyingType ) ,
this . BaseContract . IsReference ) ,
type ) ;
}
else
{
isReference = dataContractAttribute . IsReference ;
}
}
else
{
isReference = this . BaseContract . IsReference ;
}
}
else if ( hasDataContractAttribute )
{
if ( dataContractAttribute . IsReference )
isReference = dataContractAttribute . IsReference ;
}
if ( isReference & & type . IsValueType )
{
DataContract . ThrowInvalidDataContractException (
SR . GetString ( SR . ValueTypeCannotHaveIsReference ,
DataContract . GetClrTypeFullName ( type ) ,
true ,
false ) ,
type ) ;
return ;
}
this . IsReference = isReference ;
}
void ImportDataMembers ( )
{
Type type = this . UnderlyingType ;
EnsureIsReferenceImported ( type ) ;
List < DataMember > tempMembers = new List < DataMember > ( ) ;
Dictionary < string , DataMember > memberNamesTable = new Dictionary < string , DataMember > ( ) ;
MemberInfo [ ] memberInfos ;
if ( this . isNonAttributedType )
{
memberInfos = type . GetMembers ( BindingFlags . DeclaredOnly | BindingFlags . Instance | BindingFlags . Public ) ;
}
else
{
memberInfos = type . GetMembers ( BindingFlags . DeclaredOnly | BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic ) ;
}
for ( int i = 0 ; i < memberInfos . Length ; i + + )
{
MemberInfo member = memberInfos [ i ] ;
if ( HasDataContract )
{
object [ ] memberAttributes = member . GetCustomAttributes ( typeof ( DataMemberAttribute ) , false ) ;
if ( memberAttributes ! = null & & memberAttributes . Length > 0 )
{
if ( memberAttributes . Length > 1 )
ThrowInvalidDataContractException ( SR . GetString ( SR . TooManyDataMembers , DataContract . GetClrTypeFullName ( member . DeclaringType ) , member . Name ) ) ;
DataMember memberContract = new DataMember ( member ) ;
if ( member . MemberType = = MemberTypes . Property )
{
PropertyInfo property = ( PropertyInfo ) member ;
MethodInfo getMethod = property . GetGetMethod ( true ) ;
if ( getMethod ! = null & & IsMethodOverriding ( getMethod ) )
continue ;
MethodInfo setMethod = property . GetSetMethod ( true ) ;
if ( setMethod ! = null & & IsMethodOverriding ( setMethod ) )
continue ;
if ( getMethod = = null )
ThrowInvalidDataContractException ( SR . GetString ( SR . NoGetMethodForProperty , property . DeclaringType , property . Name ) ) ;
if ( setMethod = = null )
{
if ( ! SetIfGetOnlyCollection ( memberContract , skipIfReadOnlyContract : false ) )
{
this . serializationExceptionMessage = SR . GetString ( SR . NoSetMethodForProperty , property . DeclaringType , property . Name ) ;
}
}
if ( getMethod . GetParameters ( ) . Length > 0 )
ThrowInvalidDataContractException ( SR . GetString ( SR . IndexedPropertyCannotBeSerialized , property . DeclaringType , property . Name ) ) ;
}
else if ( member . MemberType ! = MemberTypes . Field )
ThrowInvalidDataContractException ( SR . GetString ( SR . InvalidMember , DataContract . GetClrTypeFullName ( type ) , member . Name ) ) ;
DataMemberAttribute memberAttribute = ( DataMemberAttribute ) memberAttributes [ 0 ] ;
if ( memberAttribute . IsNameSetExplicitly )
{
if ( memberAttribute . Name = = null | | memberAttribute . Name . Length = = 0 )
ThrowInvalidDataContractException ( SR . GetString ( SR . InvalidDataMemberName , member . Name , DataContract . GetClrTypeFullName ( type ) ) ) ;
memberContract . Name = memberAttribute . Name ;
}
else
memberContract . Name = member . Name ;
memberContract . Name = DataContract . EncodeLocalName ( memberContract . Name ) ;
memberContract . IsNullable = DataContract . IsTypeNullable ( memberContract . MemberType ) ;
memberContract . IsRequired = memberAttribute . IsRequired ;
if ( memberAttribute . IsRequired & & this . IsReference )
{
ThrowInvalidDataContractException (
SR . GetString ( SR . IsRequiredDataMemberOnIsReferenceDataContractType ,
DataContract . GetClrTypeFullName ( member . DeclaringType ) ,
member . Name , true ) , type ) ;
}
memberContract . EmitDefaultValue = memberAttribute . EmitDefaultValue ;
memberContract . Order = memberAttribute . Order ;
CheckAndAddMember ( tempMembers , memberContract , memberNamesTable ) ;
}
}
else if ( this . isNonAttributedType )
{
FieldInfo field = member as FieldInfo ;
PropertyInfo property = member as PropertyInfo ;
if ( ( field = = null & & property = = null ) | | ( field ! = null & & field . IsInitOnly ) )
continue ;
object [ ] memberAttributes = member . GetCustomAttributes ( typeof ( IgnoreDataMemberAttribute ) , false ) ;
if ( memberAttributes ! = null & & memberAttributes . Length > 0 )
{
if ( memberAttributes . Length > 1 )
ThrowInvalidDataContractException ( SR . GetString ( SR . TooManyIgnoreDataMemberAttributes , DataContract . GetClrTypeFullName ( member . DeclaringType ) , member . Name ) ) ;
else
continue ;
}
DataMember memberContract = new DataMember ( member ) ;
if ( property ! = null )
{
MethodInfo getMethod = property . GetGetMethod ( ) ;
if ( getMethod = = null | | IsMethodOverriding ( getMethod ) | | getMethod . GetParameters ( ) . Length > 0 )
continue ;
MethodInfo setMethod = property . GetSetMethod ( true ) ;
if ( setMethod = = null )
{
// if the collection doesn't have the 'Add' method, we will skip it, for compatibility with 4.0
if ( ! SetIfGetOnlyCollection ( memberContract , skipIfReadOnlyContract : true ) )
continue ;
}
else
{
if ( ! setMethod . IsPublic | | IsMethodOverriding ( setMethod ) )
continue ;
}
//skip ExtensionData member of type ExtensionDataObject if IExtensibleDataObject is implemented in non-attributed type
if ( this . hasExtensionData & & memberContract . MemberType = = Globals . TypeOfExtensionDataObject
& & member . Name = = Globals . ExtensionDataObjectPropertyName )
continue ;
}
memberContract . Name = DataContract . EncodeLocalName ( member . Name ) ;
memberContract . IsNullable = DataContract . IsTypeNullable ( memberContract . MemberType ) ;
CheckAndAddMember ( tempMembers , memberContract , memberNamesTable ) ;
}
else
{
FieldInfo field = member as FieldInfo ;
if ( field ! = null & & ! field . IsNotSerialized )
{
DataMember memberContract = new DataMember ( member ) ;
memberContract . Name = DataContract . EncodeLocalName ( member . Name ) ;
object [ ] optionalFields = field . GetCustomAttributes ( Globals . TypeOfOptionalFieldAttribute , false ) ;
if ( optionalFields = = null | | optionalFields . Length = = 0 )
{
if ( this . IsReference )
{
ThrowInvalidDataContractException (
SR . GetString ( SR . NonOptionalFieldMemberOnIsReferenceSerializableType ,
DataContract . GetClrTypeFullName ( member . DeclaringType ) ,
member . Name , true ) , type ) ;
}
memberContract . IsRequired = true ;
}
memberContract . IsNullable = DataContract . IsTypeNullable ( memberContract . MemberType ) ;
CheckAndAddMember ( tempMembers , memberContract , memberNamesTable ) ;
}
}
}
if ( tempMembers . Count > 1 )
tempMembers . Sort ( DataMemberComparer . Singleton ) ;
SetIfMembersHaveConflict ( tempMembers ) ;
Thread . MemoryBarrier ( ) ;
members = tempMembers ;
}
bool SetIfGetOnlyCollection ( DataMember memberContract , bool skipIfReadOnlyContract )
{
//OK to call IsCollection here since the use of surrogated collection types is not supported in get-only scenarios
if ( CollectionDataContract . IsCollection ( memberContract . MemberType , false /*isConstructorRequired*/ , skipIfReadOnlyContract ) & & ! memberContract . MemberType . IsValueType )
{
memberContract . IsGetOnlyCollection = true ;
return true ;
}
return false ;
}
void SetIfMembersHaveConflict ( List < DataMember > members )
{
if ( BaseContract = = null )
return ;
int baseTypeIndex = 0 ;
List < Member > membersInHierarchy = new List < Member > ( ) ;
foreach ( DataMember member in members )
{
membersInHierarchy . Add ( new Member ( member , this . StableName . Namespace , baseTypeIndex ) ) ;
}
ClassDataContract currContract = BaseContract ;
while ( currContract ! = null )
{
baseTypeIndex + + ;
foreach ( DataMember member in currContract . Members )
{
membersInHierarchy . Add ( new Member ( member , currContract . StableName . Namespace , baseTypeIndex ) ) ;
}
currContract = currContract . BaseContract ;
}
IComparer < Member > comparer = DataMemberConflictComparer . Singleton ;
membersInHierarchy . Sort ( comparer ) ;
for ( int i = 0 ; i < membersInHierarchy . Count - 1 ; i + + )
{
int startIndex = i ;
int endIndex = i ;
bool hasConflictingType = false ;
while ( endIndex < membersInHierarchy . Count - 1
& & String . CompareOrdinal ( membersInHierarchy [ endIndex ] . member . Name , membersInHierarchy [ endIndex + 1 ] . member . Name ) = = 0
& & String . CompareOrdinal ( membersInHierarchy [ endIndex ] . ns , membersInHierarchy [ endIndex + 1 ] . ns ) = = 0 )
{
membersInHierarchy [ endIndex ] . member . ConflictingMember = membersInHierarchy [ endIndex + 1 ] . member ;
if ( ! hasConflictingType )
{
if ( membersInHierarchy [ endIndex + 1 ] . member . HasConflictingNameAndType )
{
hasConflictingType = true ;
}
else
{
hasConflictingType = ( membersInHierarchy [ endIndex ] . member . MemberType ! = membersInHierarchy [ endIndex + 1 ] . member . MemberType ) ;
}
}
endIndex + + ;
}
if ( hasConflictingType )
{
for ( int j = startIndex ; j < = endIndex ; j + + )
{
membersInHierarchy [ j ] . member . HasConflictingNameAndType = true ;
}
}
i = endIndex + 1 ;
}
}
[ Fx . Tag . SecurityNote ( Critical = "Sets the critical hasDataContract field." ,
Safe = "Uses a trusted critical API (DataContract.GetStableName) to calculate the value, does not accept the value from the caller." ) ]
[SecuritySafeCritical]
XmlQualifiedName GetStableNameAndSetHasDataContract ( Type type )
{
return DataContract . GetStableName ( type , out this . hasDataContract ) ;
}
[ Fx . Tag . SecurityNote ( Miscellaneous = "RequiresReview - callers may need to depend on isNonAttributedType for a security decision."
+ "isNonAttributedType must be calculated correctly."
+ "SetIsNonAttributedType should not be called before GetStableNameAndSetHasDataContract since it is dependent on the correct calculation of hasDataContract." ,
Safe = "Does not let caller influence isNonAttributedType calculation; no harm in leaking value." ) ]
void SetIsNonAttributedType ( Type type )
{
this . isNonAttributedType = ! type . IsSerializable & & ! this . hasDataContract & & IsNonAttributedTypeValidForSerialization ( type ) ;
}
static bool IsMethodOverriding ( MethodInfo method )
{
return method . IsVirtual & & ( ( method . Attributes & MethodAttributes . NewSlot ) = = 0 ) ;
}
internal void EnsureMethodsImported ( )
{
if ( ! isMethodChecked & & UnderlyingType ! = null )
{
lock ( this )
{
if ( ! isMethodChecked )
{
Type type = this . UnderlyingType ;
MethodInfo [ ] methods = type . GetMethods ( BindingFlags . DeclaredOnly | BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic ) ;
for ( int i = 0 ; i < methods . Length ; i + + )
{
MethodInfo method = methods [ i ] ;
Type prevAttributeType = null ;
ParameterInfo [ ] parameters = method . GetParameters ( ) ;
if ( HasExtensionData & & IsValidExtensionDataSetMethod ( method , parameters ) )
{
if ( method . Name = = Globals . ExtensionDataSetExplicitMethod | | ! method . IsPublic )
extensionDataSetMethod = XmlFormatGeneratorStatics . ExtensionDataSetExplicitMethodInfo ;
else
extensionDataSetMethod = method ;
}
if ( IsValidCallback ( method , parameters , Globals . TypeOfOnSerializingAttribute , onSerializing , ref prevAttributeType ) )
onSerializing = method ;
if ( IsValidCallback ( method , parameters , Globals . TypeOfOnSerializedAttribute , onSerialized , ref prevAttributeType ) )
onSerialized = method ;
if ( IsValidCallback ( method , parameters , Globals . TypeOfOnDeserializingAttribute , onDeserializing , ref prevAttributeType ) )
onDeserializing = method ;
if ( IsValidCallback ( method , parameters , Globals . TypeOfOnDeserializedAttribute , onDeserialized , ref prevAttributeType ) )
onDeserialized = method ;
}
Thread . MemoryBarrier ( ) ;
isMethodChecked = true ;
}
}
}
}
bool IsValidExtensionDataSetMethod ( MethodInfo method , ParameterInfo [ ] parameters )
{
if ( method . Name = = Globals . ExtensionDataSetExplicitMethod | | method . Name = = Globals . ExtensionDataSetMethod )
{
if ( extensionDataSetMethod ! = null )
ThrowInvalidDataContractException ( SR . GetString ( SR . DuplicateExtensionDataSetMethod , method , extensionDataSetMethod , DataContract . GetClrTypeFullName ( method . DeclaringType ) ) ) ;
if ( method . ReturnType ! = Globals . TypeOfVoid )
DataContract . ThrowInvalidDataContractException ( SR . GetString ( SR . ExtensionDataSetMustReturnVoid , DataContract . GetClrTypeFullName ( method . DeclaringType ) , method ) , method . DeclaringType ) ;
if ( parameters = = null | | parameters . Length ! = 1 | | parameters [ 0 ] . ParameterType ! = Globals . TypeOfExtensionDataObject )
DataContract . ThrowInvalidDataContractException ( SR . GetString ( SR . ExtensionDataSetParameterInvalid , DataContract . GetClrTypeFullName ( method . DeclaringType ) , method , Globals . TypeOfExtensionDataObject ) , method . DeclaringType ) ;
return true ;
}
return false ;
}
static bool IsValidCallback ( MethodInfo method , ParameterInfo [ ] parameters , Type attributeType , MethodInfo currentCallback , ref Type prevAttributeType )
{
if ( method . IsDefined ( attributeType , false ) )
{
if ( currentCallback ! = null )
DataContract . ThrowInvalidDataContractException ( SR . GetString ( SR . DuplicateCallback , method , currentCallback , DataContract . GetClrTypeFullName ( method . DeclaringType ) , attributeType ) , method . DeclaringType ) ;
else if ( prevAttributeType ! = null )
DataContract . ThrowInvalidDataContractException ( SR . GetString ( SR . DuplicateAttribute , prevAttributeType , attributeType , DataContract . GetClrTypeFullName ( method . DeclaringType ) , method ) , method . DeclaringType ) ;
else if ( method . IsVirtual )
DataContract . ThrowInvalidDataContractException ( SR . GetString ( SR . CallbacksCannotBeVirtualMethods , method , DataContract . GetClrTypeFullName ( method . DeclaringType ) , attributeType ) , method . DeclaringType ) ;
else
{
if ( method . ReturnType ! = Globals . TypeOfVoid )
DataContract . ThrowInvalidDataContractException ( SR . GetString ( SR . CallbackMustReturnVoid , DataContract . GetClrTypeFullName ( method . DeclaringType ) , method ) , method . DeclaringType ) ;
if ( parameters = = null | | parameters . Length ! = 1 | | parameters [ 0 ] . ParameterType ! = Globals . TypeOfStreamingContext )
DataContract . ThrowInvalidDataContractException ( SR . GetString ( SR . CallbackParameterInvalid , DataContract . GetClrTypeFullName ( method . DeclaringType ) , method , Globals . TypeOfStreamingContext ) , method . DeclaringType ) ;
prevAttributeType = attributeType ;
}
return true ;
}
return false ;
}
internal ClassDataContract BaseContract
{
get { return baseContract ; }
set
{
baseContract = value ;
if ( baseContract ! = null & & IsValueType )
ThrowInvalidDataContractException ( SR . GetString ( SR . ValueTypeCannotHaveBaseType , StableName . Name , StableName . Namespace , baseContract . StableName . Name , baseContract . StableName . Namespace ) ) ;
}
}
internal List < DataMember > Members
{
get { return members ; }
set { members = value ; }
}
internal MethodInfo OnSerializing
{
get
{
EnsureMethodsImported ( ) ;
return onSerializing ;
}
}
internal MethodInfo OnSerialized
{
get
{
EnsureMethodsImported ( ) ;
return onSerialized ;
}
}
internal MethodInfo OnDeserializing
{
get
{
EnsureMethodsImported ( ) ;
return onDeserializing ;
}
}
internal MethodInfo OnDeserialized
{
get
{
EnsureMethodsImported ( ) ;
return onDeserialized ;
}
}
internal MethodInfo ExtensionDataSetMethod
{
get
{
EnsureMethodsImported ( ) ;
return extensionDataSetMethod ;
}
}
internal override DataContractDictionary KnownDataContracts
{
get
{
if ( ! isKnownTypeAttributeChecked & & UnderlyingType ! = null )
{
lock ( this )
{
if ( ! isKnownTypeAttributeChecked )
{
knownDataContracts = DataContract . ImportKnownTypeAttributes ( this . UnderlyingType ) ;
Thread . MemoryBarrier ( ) ;
isKnownTypeAttributeChecked = true ;
}
}
}
return knownDataContracts ;
}
set { knownDataContracts = value ; }
}
internal string SerializationExceptionMessage
{
get { return serializationExceptionMessage ; }
}
internal string DeserializationExceptionMessage
{
get
{
if ( serializationExceptionMessage = = null )
{
return null ;
}
else
{
return SR . GetString ( SR . ReadOnlyClassDeserialization , this . serializationExceptionMessage ) ;
}
}
}
internal override bool IsISerializable
{
get { return isISerializable ; }
set { isISerializable = value ; }
}
internal bool HasDataContract
{
get { return hasDataContract ; }
}
internal bool HasExtensionData
{
get { return hasExtensionData ; }
}
internal bool IsNonAttributedType
{
get { return isNonAttributedType ; }
}
internal ConstructorInfo GetISerializableConstructor ( )
{
if ( ! IsISerializable )
return null ;
ConstructorInfo ctor = UnderlyingType . GetConstructor ( Globals . ScanAllMembers , null , SerInfoCtorArgs , null ) ;
if ( ctor = = null )
throw System . Runtime . Serialization . DiagnosticUtility . ExceptionUtility . ThrowHelperError ( XmlObjectSerializer . CreateSerializationException ( SR . GetString ( SR . SerializationInfo_ConstructorNotFound , DataContract . GetClrTypeFullName ( UnderlyingType ) ) ) ) ;
return ctor ;
}
internal ConstructorInfo GetNonAttributedTypeConstructor ( )
{
if ( ! this . IsNonAttributedType )
return null ;
Type type = UnderlyingType ;
if ( type . IsValueType )
return null ;
ConstructorInfo ctor = type . GetConstructor ( BindingFlags . Instance | BindingFlags . NonPublic | BindingFlags . Public , null , Globals . EmptyTypeArray , null ) ;
if ( ctor = = null )
throw System . Runtime . Serialization . DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidDataContractException ( SR . GetString ( SR . NonAttributedSerializableTypesMustHaveDefaultConstructor , DataContract . GetClrTypeFullName ( type ) ) ) ) ;
return ctor ;
}
internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate
{
get { return xmlFormatWriterDelegate ; }
set { xmlFormatWriterDelegate = value ; }
}
internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate
{
get { return xmlFormatReaderDelegate ; }
set { xmlFormatReaderDelegate = value ; }
}
public XmlDictionaryString [ ] ChildElementNamespaces
{
get { return childElementNamespaces ; }
set { childElementNamespaces = value ; }
}
static Type [ ] serInfoCtorArgs ;
static Type [ ] SerInfoCtorArgs
{
get
{
if ( serInfoCtorArgs = = null )
serInfoCtorArgs = new Type [ ] { typeof ( SerializationInfo ) , typeof ( StreamingContext ) } ;
return serInfoCtorArgs ;
}
}
internal struct Member
{
internal Member ( DataMember member , string ns , int baseTypeIndex )
{
this . member = member ;
this . ns = ns ;
this . baseTypeIndex = baseTypeIndex ;
}
internal DataMember member ;
internal string ns ;
internal int baseTypeIndex ;
}
internal class DataMemberConflictComparer : IComparer < Member >
{
public int Compare ( Member x , Member y )
{
int nsCompare = String . CompareOrdinal ( x . ns , y . ns ) ;
if ( nsCompare ! = 0 )
return nsCompare ;
int nameCompare = String . CompareOrdinal ( x . member . Name , y . member . Name ) ;
if ( nameCompare ! = 0 )
return nameCompare ;
return x . baseTypeIndex - y . baseTypeIndex ;
}
internal static DataMemberConflictComparer Singleton = new DataMemberConflictComparer ( ) ;
}
}
[ Fx . Tag . SecurityNote ( Critical = "Sets critical properties on ClassDataContract ." ,
Safe = "Called during schema import/code generation." ) ]
[SecuritySafeCritical]
internal override DataContract BindGenericParameters ( DataContract [ ] paramContracts , Dictionary < DataContract , DataContract > boundContracts )
{
Type type = UnderlyingType ;
if ( ! type . IsGenericType | | ! type . ContainsGenericParameters )
return this ;
lock ( this )
{
DataContract boundContract ;
if ( boundContracts . TryGetValue ( this , out boundContract ) )
return boundContract ;
ClassDataContract boundClassContract = new ClassDataContract ( ) ;
boundContracts . Add ( this , boundClassContract ) ;
XmlQualifiedName stableName ;
object [ ] genericParams ;
if ( type . IsGenericTypeDefinition )
{
stableName = this . StableName ;
genericParams = paramContracts ;
}
else
{
//partial Generic: Construct stable name from its open generic type definition
stableName = DataContract . GetStableName ( type . GetGenericTypeDefinition ( ) ) ;
Type [ ] paramTypes = type . GetGenericArguments ( ) ;
genericParams = new object [ paramTypes . Length ] ;
for ( int i = 0 ; i < paramTypes . Length ; i + + )
{
Type paramType = paramTypes [ i ] ;
if ( paramType . IsGenericParameter )
genericParams [ i ] = paramContracts [ paramType . GenericParameterPosition ] ;
else
genericParams [ i ] = paramType ;
}
}
boundClassContract . StableName = CreateQualifiedName ( DataContract . ExpandGenericParameters ( XmlConvert . DecodeName ( stableName . Name ) , new GenericNameProvider ( DataContract . GetClrTypeFullName ( this . UnderlyingType ) , genericParams ) ) , stableName . Namespace ) ;
if ( BaseContract ! = null )
boundClassContract . BaseContract = ( ClassDataContract ) BaseContract . BindGenericParameters ( paramContracts , boundContracts ) ;
boundClassContract . IsISerializable = this . IsISerializable ;
boundClassContract . IsValueType = this . IsValueType ;
boundClassContract . IsReference = this . IsReference ;
if ( Members ! = null )
{
boundClassContract . Members = new List < DataMember > ( Members . Count ) ;
foreach ( DataMember member in Members )
boundClassContract . Members . Add ( member . BindGenericParameters ( paramContracts , boundContracts ) ) ;
}
return boundClassContract ;
}
}
internal override bool Equals ( object other , Dictionary < DataContractPairKey , object > checkedContracts )
{
if ( IsEqualOrChecked ( other , checkedContracts ) )
return true ;
if ( base . Equals ( other , checkedContracts ) )
{
ClassDataContract dataContract = other as ClassDataContract ;
if ( dataContract ! = null )
{
if ( IsISerializable )
{
if ( ! dataContract . IsISerializable )
return false ;
}
else
{
if ( dataContract . IsISerializable )
return false ;
if ( Members = = null )
{
if ( dataContract . Members ! = null )
{
// check that all the datamembers in dataContract.Members are optional
if ( ! IsEveryDataMemberOptional ( dataContract . Members ) )
return false ;
}
}
else if ( dataContract . Members = = null )
{
// check that all the datamembers in Members are optional
if ( ! IsEveryDataMemberOptional ( Members ) )
return false ;
}
else
{
Dictionary < string , DataMember > membersDictionary = new Dictionary < string , DataMember > ( Members . Count ) ;
List < DataMember > dataContractMembersList = new List < DataMember > ( ) ;
for ( int i = 0 ; i < Members . Count ; i + + )
{
membersDictionary . Add ( Members [ i ] . Name , Members [ i ] ) ;
}
for ( int i = 0 ; i < dataContract . Members . Count ; i + + )
{
// check that all datamembers common to both datacontracts match
DataMember dataMember ;
if ( membersDictionary . TryGetValue ( dataContract . Members [ i ] . Name , out dataMember ) )
{
if ( dataMember . Equals ( dataContract . Members [ i ] , checkedContracts ) )
{
membersDictionary . Remove ( dataMember . Name ) ;
}
else
{
return false ;
}
}
// otherwise save the non-matching datamembers for later verification
else
{
dataContractMembersList . Add ( dataContract . Members [ i ] ) ;
}
}
// check that datamembers left over from either datacontract are optional
if ( ! IsEveryDataMemberOptional ( membersDictionary . Values ) )
return false ;
if ( ! IsEveryDataMemberOptional ( dataContractMembersList ) )
return false ;
}
}
if ( BaseContract = = null )
return ( dataContract . BaseContract = = null ) ;
else if ( dataContract . BaseContract = = null )
return false ;
else
return BaseContract . Equals ( dataContract . BaseContract , checkedContracts ) ;
}
}
return false ;
}
bool IsEveryDataMemberOptional ( IEnumerable < DataMember > dataMembers )
{
foreach ( DataMember dataMember in dataMembers )
{
if ( dataMember . IsRequired )
return false ;
}
return true ;
}
public override int GetHashCode ( )
{
return base . GetHashCode ( ) ;
}
internal class DataMemberComparer : IComparer < DataMember >
{
public int Compare ( DataMember x , DataMember y )
{
int orderCompare = x . Order - y . Order ;
if ( orderCompare ! = 0 )
return orderCompare ;
return String . CompareOrdinal ( x . Name , y . Name ) ;
}
internal static DataMemberComparer Singleton = new DataMemberComparer ( ) ;
}
}
}