Files
acceptance-tests
data
debian
docs
external
ikvm-native
libgc
llvm
m4
man
mcs
build
class
Accessibility
Commons.Xml.Relaxng
Cscompmgd
CustomMarshalers
Facades
I18N
IBM.Data.DB2
ICSharpCode.SharpZipLib
Microsoft.Build
Microsoft.Build.Engine
Microsoft.Build.Framework
Microsoft.Build.Tasks
Microsoft.Build.Utilities
Microsoft.CSharp
Microsoft.NuGet.Build.Tasks
Microsoft.VisualC
Microsoft.Web.Infrastructure
MicrosoftAjaxLibrary
Mono.Btls.Interface
Mono.C5
Mono.CSharp
Mono.Cairo
Mono.Cecil
Mono.Cecil.Mdb
Mono.CodeContracts
Mono.CompilerServices.SymbolWriter
Mono.Data.Sqlite
Mono.Data.Tds
Mono.Debugger.Soft
Mono.Http
Mono.Management
Mono.Messaging
Mono.Messaging.RabbitMQ
Mono.Options
Mono.Parallel
Mono.Posix
Mono.Profiler.Log
Mono.Runtime.Tests
Mono.Security
Mono.Security.Win32
Mono.Simd
Mono.Tasklets
Mono.WebBrowser
Mono.XBuild.Tasks
Novell.Directory.Ldap
PEAPI
RabbitMQ.Client
SMDiagnostics
System
System.ComponentModel.Composition.4.5
System.ComponentModel.DataAnnotations
System.Configuration
System.Configuration.Install
System.Core
System.Data
System.Data.DataSetExtensions
System.Data.Entity
System.Data.Linq
System.Data.OracleClient
System.Data.Services
System.Data.Services.Client
System.Deployment
System.Design
System.DirectoryServices
System.DirectoryServices.Protocols
System.Drawing
System.Drawing.Design
System.Dynamic
System.EnterpriseServices
System.IO.Compression
System.IO.Compression.FileSystem
System.IdentityModel
System.IdentityModel.Selectors
System.Json
System.Json.Microsoft
System.Management
System.Messaging
System.Net
System.Net.Http
System.Net.Http.Formatting
System.Net.Http.WebRequest
System.Net.Http.WinHttpHandler
System.Numerics
System.Numerics.Vectors
System.Reactive.Core
System.Reactive.Debugger
System.Reactive.Experimental
System.Reactive.Interfaces
System.Reactive.Linq
System.Reactive.Observable.Aliases
System.Reactive.PlatformServices
System.Reactive.Providers
System.Reactive.Runtime.Remoting
System.Reactive.Windows.Forms
System.Reactive.Windows.Threading
System.Reflection.Context
System.Runtime.Caching
System.Runtime.CompilerServices.Unsafe
System.Runtime.DurableInstancing
System.Runtime.Remoting
System.Runtime.Serialization
System.Runtime.Serialization.Formatters.Soap
System.Security
System.ServiceModel
System.ServiceModel.Activation
System.ServiceModel.Discovery
System.ServiceModel.Internals
System.ServiceModel.Routing
System.ServiceModel.Web
System.ServiceProcess
System.Threading.Tasks.Dataflow
System.Transactions
System.Web
System.Web.Abstractions
System.Web.ApplicationServices
System.Web.DynamicData
System.Web.Extensions
System.Web.Extensions.Design
System.Web.Http
System.Web.Http.SelfHost
System.Web.Http.WebHost
System.Web.Mobile
System.Web.Mvc3
System.Web.Razor
System.Web.RegularExpressions
System.Web.Routing
System.Web.Services
System.Web.WebPages
System.Web.WebPages.Deployment
System.Web.WebPages.Razor
System.Windows
System.Windows.Forms
System.Windows.Forms.DataVisualization
System.Workflow.Activities
System.Workflow.ComponentModel
System.Workflow.Runtime
System.XML
System.Xaml
System.Xml.Linq
System.Xml.Serialization
SystemWebTestShim
WebMatrix.Data
WindowsBase
aot-compiler
corlib
dlr
doc
legacy
lib
monodoc
notes
reference-assemblies
referencesource
SMDiagnostics
System
System.Activities
System.Activities.Core.Presentation
System.Activities.DurableInstancing
System.Activities.Presentation
System.ComponentModel.DataAnnotations
System.Configuration
System.Core
System.Data
System.Data.DataSetExtensions
System.Data.Entity
System.Data.Entity.Design
System.Data.Linq
System.Data.SqlXml
System.IdentityModel
System.IdentityModel.Selectors
System.Net
System.Numerics
System.Runtime.Caching
System.Runtime.DurableInstancing
System.Runtime.Serialization
System
Runtime
Serialization
Configuration
Diagnostics
Json
AppSettings.cs
Attributes.cs
BitFlagsGenerator.cs
ClassDataContract.cs
CodeExporter.cs.REMOVED.git-id
CodeGenerator.cs
CollectionDataContract.cs
CollectionDataContractAttribute.cs
ContractCodeDomInfo.cs
ContractNamespaceAttribute.cs
DataContract.cs.REMOVED.git-id
DataContractAttribute.cs
DataContractResolver.cs
DataContractSerializer.cs
DataContractSerializerSettings.cs
DataContractSet.cs
DataMember.cs
DataMemberAttribute.cs
DateTimeFormat.cs
DateTimeOffsetAdapter.cs
DictionaryGlobals.cs
EmitTypeInformation.cs
EnumDataContract.cs
EnumMemberAttribute.cs
ExportOptions.cs
ExtensionDataObject.cs
ExtensionDataReader.cs
GenericParameterDataContract.cs
Globals.cs
HybridObjectCache.cs
IDataContractSurrogate.cs
IExtensibleDataObject.cs
IgnoreDataMemberAttribute.cs
ImportOptions.cs
InvalidDataContractException.cs
KnownTypeAttribute.cs
KnownTypeDataContractResolver.cs
NetDataContractSerializer.cs
ObjectReferenceStack.cs
ObjectToIdCache.cs
PrimitiveDataContract.cs
SchemaExporter.cs
SchemaHelper.cs
SchemaImporter.cs
ScopedKnownTypes.cs
SerializationMode.cs
SerializationPermissionNotRequiredAttribute.cs
SerializationTrace.cs
SpecialTypeDataContract.cs
SurrogateDataContract.cs
TypeInformation.cs
XPathQueryGenerator.cs
XmlDataContract.cs
XmlFormatGeneratorStatics.cs
XmlFormatReaderGenerator.cs
XmlFormatWriterGenerator.cs
XmlObjectSerializer.cs
XmlObjectSerializerContext.cs
XmlObjectSerializerReadContext.cs
XmlObjectSerializerReadContextComplex.cs
XmlObjectSerializerWriteContext.cs
XmlObjectSerializerWriteContextComplex.cs
XmlReaderDelegator.cs
XmlSerializableReader.cs
XmlSerializableServices.cs
XmlSerializableWriter.cs
XmlWriterDelegator.cs
XsdDataContractExporter.cs
XsdDataContractImporter.cs
Text
Xml
System.Runtime.Serialization.txt
TD.Designer.cs
System.ServiceModel
System.ServiceModel.Activation
System.ServiceModel.Activities
System.ServiceModel.Channels
System.ServiceModel.Discovery
System.ServiceModel.Internals
System.ServiceModel.Routing
System.ServiceModel.WasHosting
System.ServiceModel.Web
System.Web
System.Web.ApplicationServices
System.Web.DataVisualization
System.Web.DynamicData
System.Web.Entity
System.Web.Entity.Design
System.Web.Extensions
System.Web.Mobile
System.Web.Routing
System.Web.Services
System.Workflow.Activities
System.Workflow.ComponentModel
System.Workflow.Runtime
System.WorkflowServices
System.Xaml.Hosting
System.Xml
System.Xml.Linq
XamlBuildTask
mscorlib
LICENSE.txt
PATENTS.TXT
README.Mono.md
README.md
test-helpers
LICENSE
Makefile
Open.snk
README
ecma.pub
mono.pub
mono.snk
msfinal.pub
reactive.pub
silverlight.pub
winfx.pub
winfx3.pub
docs
errors
ilasm
jay
mcs
nunit24
packages
tests
tools
AUTHORS
COPYING
INSTALL.txt
Makefile
MonoIcon.png
README
ScalableMonoIcon.svg
mkinstalldirs
mk
mono
msvc
po
runtime
samples
scripts
support
tools
COPYING.LIB
LICENSE
Makefile.am
Makefile.in
NEWS
README.md
acinclude.m4
aclocal.m4
autogen.sh
code_of_conduct.md
compile
config.guess
config.h.in
config.rpath
config.sub
configure.REMOVED.git-id
configure.ac.REMOVED.git-id
depcomp
install-sh
ltmain.sh.REMOVED.git-id
missing
mkinstalldirs
mono-uninstalled.pc.in
test-driver
winconfig.h

1525 lines
69 KiB
C#
Raw Normal View History

//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Runtime.Serialization
{
using System;
using System.Collections;
using System.Diagnostics;
using System.Collections.Generic;
using System.IO;
using System.Globalization;
using System.Reflection;
using System.Threading;
using System.Xml;
#if !NO_CONFIGURATION
using System.Runtime.Serialization.Configuration;
#endif
using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
using System.Security;
using System.Security.Permissions;
[DataContract(Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
#if USE_REFEMIT
public struct KeyValue<K, V>
#else
internal struct KeyValue<K, V>
#endif
{
K key;
V value;
internal KeyValue(K key, V value)
{
this.key = key;
this.value = value;
}
[DataMember(IsRequired = true)]
public K Key
{
get { return key; }
set { key = value; }
}
[DataMember(IsRequired = true)]
public V Value
{
get { return value; }
set { this.value = value; }
}
}
internal enum CollectionKind : byte
{
None,
GenericDictionary,
Dictionary,
GenericList,
GenericCollection,
List,
GenericEnumerable,
Collection,
Enumerable,
Array,
}
#if USE_REFEMIT
public sealed class CollectionDataContract : DataContract
#else
internal sealed class CollectionDataContract : DataContract
#endif
{
[Fx.Tag.SecurityNote(Critical = "XmlDictionaryString representing the XML element name for collection items."
+ "Statically cached and used from IL generated code.")]
[SecurityCritical]
XmlDictionaryString collectionItemName;
[Fx.Tag.SecurityNote(Critical = "XmlDictionaryString representing the XML namespace for collection items."
+ "Statically cached and used from IL generated code.")]
[SecurityCritical]
XmlDictionaryString childElementNamespace;
[Fx.Tag.SecurityNote(Critical = "Internal DataContract representing the contract for collection items."
+ "Statically cached and used from IL generated code.")]
[SecurityCritical]
DataContract itemContract;
[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.")]
[SecurityCritical]
CollectionDataContractCriticalHelper helper;
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
Safe = "Doesn't leak anything.")]
[SecuritySafeCritical]
internal CollectionDataContract(CollectionKind kind)
: base(new CollectionDataContractCriticalHelper(kind))
{
InitCollectionDataContract(this);
}
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
Safe = "Doesn't leak anything.")]
[SecuritySafeCritical]
internal CollectionDataContract(Type type)
: base(new CollectionDataContractCriticalHelper(type))
{
InitCollectionDataContract(this);
}
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
Safe = "Doesn't leak anything.")]
[SecuritySafeCritical]
internal CollectionDataContract(Type type, DataContract itemContract)
: base(new CollectionDataContractCriticalHelper(type, itemContract))
{
InitCollectionDataContract(this);
}
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
Safe = "Doesn't leak anything.")]
[SecuritySafeCritical]
CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, string serializationExceptionMessage, string deserializationExceptionMessage)
: base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage))
{
InitCollectionDataContract(GetSharedTypeContract(type));
}
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
Safe = "Doesn't leak anything.")]
[SecuritySafeCritical]
CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor)
: base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, addMethod, constructor))
{
InitCollectionDataContract(GetSharedTypeContract(type));
}
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
Safe = "Doesn't leak anything.")]
[SecuritySafeCritical]
CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor, bool isConstructorCheckRequired)
: base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, addMethod, constructor, isConstructorCheckRequired))
{
InitCollectionDataContract(GetSharedTypeContract(type));
}
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
Safe = "Doesn't leak anything.")]
[SecuritySafeCritical]
CollectionDataContract(Type type, string invalidCollectionInSharedContractMessage)
: base(new CollectionDataContractCriticalHelper(type, invalidCollectionInSharedContractMessage))
{
InitCollectionDataContract(GetSharedTypeContract(type));
}
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical fields; called from all constructors.")]
[SecurityCritical]
void InitCollectionDataContract(DataContract sharedTypeContract)
{
this.helper = base.Helper as CollectionDataContractCriticalHelper;
this.collectionItemName = helper.CollectionItemName;
if (helper.Kind == CollectionKind.Dictionary || helper.Kind == CollectionKind.GenericDictionary)
{
this.itemContract = helper.ItemContract;
}
this.helper.SharedTypeContract = sharedTypeContract;
}
void InitSharedTypeContract()
{
}
static Type[] KnownInterfaces
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical knownInterfaces property.",
Safe = "knownInterfaces only needs to be protected for write.")]
[SecuritySafeCritical]
get { return CollectionDataContractCriticalHelper.KnownInterfaces; }
}
internal CollectionKind Kind
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical kind property.",
Safe = "kind only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.Kind; }
}
internal Type ItemType
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical itemType property.",
Safe = "itemType only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.ItemType; }
}
public DataContract ItemContract
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical itemContract property.",
Safe = "itemContract only needs to be protected for write.")]
[SecuritySafeCritical]
get { return itemContract ?? helper.ItemContract; }
[Fx.Tag.SecurityNote(Critical = "Sets the critical itemContract property.")]
[SecurityCritical]
set
{
itemContract = value;
helper.ItemContract = value;
}
}
internal DataContract SharedTypeContract
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical sharedTypeContract property.",
Safe = "sharedTypeContract only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.SharedTypeContract; }
}
internal string ItemName
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical itemName property.",
Safe = "itemName only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.ItemName; }
[Fx.Tag.SecurityNote(Critical = "Sets the critical itemName property.")]
[SecurityCritical]
set { helper.ItemName = value; }
}
public XmlDictionaryString CollectionItemName
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical collectionItemName property.",
Safe = "collectionItemName only needs to be protected for write.")]
[SecuritySafeCritical]
get { return this.collectionItemName; }
}
internal string KeyName
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical keyName property.",
Safe = "keyName only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.KeyName; }
[Fx.Tag.SecurityNote(Critical = "Sets the critical keyName property.")]
[SecurityCritical]
set { helper.KeyName = value; }
}
internal string ValueName
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical valueName property.",
Safe = "valueName only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.ValueName; }
[Fx.Tag.SecurityNote(Critical = "Sets the critical valueName property.")]
[SecurityCritical]
set { helper.ValueName = value; }
}
internal bool IsDictionary
{
get { return KeyName != null; }
}
public XmlDictionaryString ChildElementNamespace
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical childElementNamespace property.",
Safe = "childElementNamespace only needs to be protected for write; initialized in getter if null.")]
[SecuritySafeCritical]
get
{
if (this.childElementNamespace == null)
{
lock (this)
{
if (this.childElementNamespace == null)
{
if (helper.ChildElementNamespace == null && !IsDictionary)
{
XmlDictionaryString tempChildElementNamespace = ClassDataContract.GetChildNamespaceToDeclare(this, ItemType, new XmlDictionary());
Thread.MemoryBarrier();
helper.ChildElementNamespace = tempChildElementNamespace;
}
this.childElementNamespace = helper.ChildElementNamespace;
}
}
}
return childElementNamespace;
}
}
internal bool IsItemTypeNullable
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical isItemTypeNullable property.",
Safe = "isItemTypeNullable only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.IsItemTypeNullable; }
[Fx.Tag.SecurityNote(Critical = "Sets the critical isItemTypeNullable property.")]
[SecurityCritical]
set { helper.IsItemTypeNullable = value; }
}
internal bool IsConstructorCheckRequired
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical isConstructorCheckRequired property.",
Safe = "isConstructorCheckRequired only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.IsConstructorCheckRequired; }
[Fx.Tag.SecurityNote(Critical = "Sets the critical isConstructorCheckRequired property.")]
[SecurityCritical]
set { helper.IsConstructorCheckRequired = value; }
}
internal MethodInfo GetEnumeratorMethod
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical getEnumeratorMethod property.",
Safe = "getEnumeratorMethod only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.GetEnumeratorMethod; }
}
internal MethodInfo AddMethod
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical addMethod property.",
Safe = "addMethod only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.AddMethod; }
}
internal ConstructorInfo Constructor
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical constructor property.",
Safe = "constructor only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.Constructor; }
}
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.")]
[SecurityCritical]
set { helper.KnownDataContracts = value; }
}
internal string InvalidCollectionInSharedContractMessage
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical invalidCollectionInSharedContractMessage property.",
Safe = "invalidCollectionInSharedContractMessage only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.InvalidCollectionInSharedContractMessage; }
}
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; }
}
bool ItemNameSetExplicit
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical itemNameSetExplicit property.",
Safe = "itemNameSetExplicit only needs to be protected for write.")]
[SecuritySafeCritical]
get { return helper.ItemNameSetExplicit; }
}
internal XmlFormatCollectionWriterDelegate 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)
{
XmlFormatCollectionWriterDelegate tempDelegate = new XmlFormatWriterGenerator().GenerateCollectionWriter(this);
Thread.MemoryBarrier();
helper.XmlFormatWriterDelegate = tempDelegate;
}
}
}
return helper.XmlFormatWriterDelegate;
}
}
internal XmlFormatCollectionReaderDelegate 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*/);
}
XmlFormatCollectionReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateCollectionReader(this);
Thread.MemoryBarrier();
helper.XmlFormatReaderDelegate = tempDelegate;
}
}
}
return helper.XmlFormatReaderDelegate;
}
}
internal XmlFormatGetOnlyCollectionReaderDelegate XmlFormatGetOnlyCollectionReaderDelegate
{
[Fx.Tag.SecurityNote(Critical = "Fetches the critical xmlFormatGetOnlyCollectionReaderDelegate property.",
Safe = "xmlFormatGetOnlyCollectionReaderDelegate only needs to be protected for write; initialized in getter if null.")]
[SecuritySafeCritical]
get
{
if (helper.XmlFormatGetOnlyCollectionReaderDelegate == null)
{
lock (this)
{
if (helper.XmlFormatGetOnlyCollectionReaderDelegate == null)
{
if (this.UnderlyingType.IsInterface && (this.Kind == CollectionKind.Enumerable || this.Kind == CollectionKind.Collection || this.Kind == CollectionKind.GenericEnumerable))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.GetOnlyCollectionMustHaveAddMethod, DataContract.GetClrTypeFullName(this.UnderlyingType))));
}
if (this.IsReadOnlyContract)
{
ThrowInvalidDataContractException(helper.DeserializationExceptionMessage, null /*type*/);
}
Fx.Assert(this.AddMethod != null || this.Kind == CollectionKind.Array, "Add method cannot be null if the collection is being used as a get-only property");
XmlFormatGetOnlyCollectionReaderDelegate tempDelegate = new XmlFormatReaderGenerator().GenerateGetOnlyCollectionReader(this);
Thread.MemoryBarrier();
helper.XmlFormatGetOnlyCollectionReaderDelegate = tempDelegate;
}
}
}
return helper.XmlFormatGetOnlyCollectionReaderDelegate;
}
}
[Fx.Tag.SecurityNote(Critical = "Holds all state used for (de)serializing collections. Since the data is cached statically, we lock down access to it.")]
#if !NO_SECURITY_ATTRIBUTES
[SecurityCritical(SecurityCriticalScope.Everything)]
#endif
class CollectionDataContractCriticalHelper : DataContract.DataContractCriticalHelper
{
static Type[] _knownInterfaces;
Type itemType;
bool isItemTypeNullable;
CollectionKind kind;
readonly MethodInfo getEnumeratorMethod, addMethod;
readonly ConstructorInfo constructor;
readonly string serializationExceptionMessage, deserializationExceptionMessage;
DataContract itemContract;
DataContract sharedTypeContract;
DataContractDictionary knownDataContracts;
bool isKnownTypeAttributeChecked;
string itemName;
bool itemNameSetExplicit;
XmlDictionaryString collectionItemName;
string keyName;
string valueName;
XmlDictionaryString childElementNamespace;
string invalidCollectionInSharedContractMessage;
XmlFormatCollectionReaderDelegate xmlFormatReaderDelegate;
XmlFormatGetOnlyCollectionReaderDelegate xmlFormatGetOnlyCollectionReaderDelegate;
XmlFormatCollectionWriterDelegate xmlFormatWriterDelegate;
bool isConstructorCheckRequired = false;
internal static Type[] KnownInterfaces
{
get
{
if (_knownInterfaces == null)
{
// Listed in priority order
_knownInterfaces = new Type[]
{
Globals.TypeOfIDictionaryGeneric,
Globals.TypeOfIDictionary,
Globals.TypeOfIListGeneric,
Globals.TypeOfICollectionGeneric,
Globals.TypeOfIList,
Globals.TypeOfIEnumerableGeneric,
Globals.TypeOfICollection,
Globals.TypeOfIEnumerable
};
}
return _knownInterfaces;
}
}
void Init(CollectionKind kind, Type itemType, CollectionDataContractAttribute collectionContractAttribute)
{
this.kind = kind;
if (itemType != null)
{
this.itemType = itemType;
this.isItemTypeNullable = DataContract.IsTypeNullable(itemType);
bool isDictionary = (kind == CollectionKind.Dictionary || kind == CollectionKind.GenericDictionary);
string itemName = null, keyName = null, valueName = null;
if (collectionContractAttribute != null)
{
if (collectionContractAttribute.IsItemNameSetExplicitly)
{
if (collectionContractAttribute.ItemName == null || collectionContractAttribute.ItemName.Length == 0)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractItemName, DataContract.GetClrTypeFullName(UnderlyingType))));
itemName = DataContract.EncodeLocalName(collectionContractAttribute.ItemName);
itemNameSetExplicit = true;
}
if (collectionContractAttribute.IsKeyNameSetExplicitly)
{
if (collectionContractAttribute.KeyName == null || collectionContractAttribute.KeyName.Length == 0)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractKeyName, DataContract.GetClrTypeFullName(UnderlyingType))));
if (!isDictionary)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractKeyNoDictionary, DataContract.GetClrTypeFullName(UnderlyingType), collectionContractAttribute.KeyName)));
keyName = DataContract.EncodeLocalName(collectionContractAttribute.KeyName);
}
if (collectionContractAttribute.IsValueNameSetExplicitly)
{
if (collectionContractAttribute.ValueName == null || collectionContractAttribute.ValueName.Length == 0)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractValueName, DataContract.GetClrTypeFullName(UnderlyingType))));
if (!isDictionary)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.InvalidCollectionContractValueNoDictionary, DataContract.GetClrTypeFullName(UnderlyingType), collectionContractAttribute.ValueName)));
valueName = DataContract.EncodeLocalName(collectionContractAttribute.ValueName);
}
}
XmlDictionary dictionary = isDictionary ? new XmlDictionary(5) : new XmlDictionary(3);
this.Name = dictionary.Add(this.StableName.Name);
this.Namespace = dictionary.Add(this.StableName.Namespace);
this.itemName = itemName ?? DataContract.GetStableName(DataContract.UnwrapNullableType(itemType)).Name;
this.collectionItemName = dictionary.Add(this.itemName);
if (isDictionary)
{
this.keyName = keyName ?? Globals.KeyLocalName;
this.valueName = valueName ?? Globals.ValueLocalName;
}
}
if (collectionContractAttribute != null)
{
this.IsReference = collectionContractAttribute.IsReference;
}
}
internal CollectionDataContractCriticalHelper(CollectionKind kind)
: base()
{
Init(kind, null, null);
}
// array
internal CollectionDataContractCriticalHelper(Type type)
: base(type)
{
if (type == Globals.TypeOfArray)
type = Globals.TypeOfObjectArray;
if (type.GetArrayRank() > 1)
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SupportForMultidimensionalArraysNotPresent)));
this.StableName = DataContract.GetStableName(type);
Init(CollectionKind.Array, type.GetElementType(), null);
}
// array
internal CollectionDataContractCriticalHelper(Type type, DataContract itemContract)
: base(type)
{
if (type.GetArrayRank() > 1)
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SupportForMultidimensionalArraysNotPresent)));
this.StableName = CreateQualifiedName(Globals.ArrayPrefix + itemContract.StableName.Name, itemContract.StableName.Namespace);
this.itemContract = itemContract;
Init(CollectionKind.Array, type.GetElementType(), null);
}
// read-only collection
internal CollectionDataContractCriticalHelper(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, string serializationExceptionMessage, string deserializationExceptionMessage)
: base(type)
{
if (getEnumeratorMethod == null)
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.CollectionMustHaveGetEnumeratorMethod, DataContract.GetClrTypeFullName(type))));
if (itemType == null)
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.CollectionMustHaveItemType, DataContract.GetClrTypeFullName(type))));
CollectionDataContractAttribute collectionContractAttribute;
this.StableName = DataContract.GetCollectionStableName(type, itemType, out collectionContractAttribute);
Init(kind, itemType, collectionContractAttribute);
this.getEnumeratorMethod = getEnumeratorMethod;
this.serializationExceptionMessage = serializationExceptionMessage;
this.deserializationExceptionMessage = deserializationExceptionMessage;
}
// collection
internal CollectionDataContractCriticalHelper(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor)
: this(type, kind, itemType, getEnumeratorMethod, (string)null, (string)null)
{
if (addMethod == null && !type.IsInterface)
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.CollectionMustHaveAddMethod, DataContract.GetClrTypeFullName(type))));
this.addMethod = addMethod;
this.constructor = constructor;
}
// collection
internal CollectionDataContractCriticalHelper(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo addMethod, ConstructorInfo constructor, bool isConstructorCheckRequired)
: this(type, kind, itemType, getEnumeratorMethod, addMethod, constructor)
{
this.isConstructorCheckRequired = isConstructorCheckRequired;
}
internal CollectionDataContractCriticalHelper(Type type, string invalidCollectionInSharedContractMessage)
: base(type)
{
Init(CollectionKind.Collection, null /*itemType*/, null);
this.invalidCollectionInSharedContractMessage = invalidCollectionInSharedContractMessage;
}
internal CollectionKind Kind
{
get { return kind; }
}
internal Type ItemType
{
get { return itemType; }
}
internal DataContract ItemContract
{
get
{
if (itemContract == null && UnderlyingType != null)
{
if (IsDictionary)
{
if (String.CompareOrdinal(KeyName, ValueName) == 0)
{
DataContract.ThrowInvalidDataContractException(
SR.GetString(SR.DupKeyValueName, DataContract.GetClrTypeFullName(UnderlyingType), KeyName),
UnderlyingType);
}
itemContract = ClassDataContract.CreateClassDataContractForKeyValue(ItemType, Namespace, new string[] { KeyName, ValueName });
// Ensure that DataContract gets added to the static DataContract cache for dictionary items
DataContract.GetDataContract(ItemType);
}
else
{
itemContract = DataContract.GetDataContract(ItemType);
}
}
return itemContract;
}
set
{
itemContract = value;
}
}
internal DataContract SharedTypeContract
{
get { return sharedTypeContract; }
set { sharedTypeContract = value; }
}
internal string ItemName
{
get { return itemName; }
set { itemName = value; }
}
internal bool IsConstructorCheckRequired
{
get { return isConstructorCheckRequired; }
set { isConstructorCheckRequired = value; }
}
public XmlDictionaryString CollectionItemName
{
get { return collectionItemName; }
}
internal string KeyName
{
get { return keyName; }
set { keyName = value; }
}
internal string ValueName
{
get { return valueName; }
set { valueName = value; }
}
internal bool IsDictionary
{
get { return KeyName != null; }
}
public string SerializationExceptionMessage
{
get { return serializationExceptionMessage; }
}
public string DeserializationExceptionMessage
{
get { return deserializationExceptionMessage; }
}
public XmlDictionaryString ChildElementNamespace
{
get { return childElementNamespace; }
set { childElementNamespace = value; }
}
internal bool IsItemTypeNullable
{
get { return isItemTypeNullable; }
set { isItemTypeNullable = value; }
}
internal MethodInfo GetEnumeratorMethod
{
get { return getEnumeratorMethod; }
}
internal MethodInfo AddMethod
{
get { return addMethod; }
}
internal ConstructorInfo Constructor
{
get { return constructor; }
}
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 InvalidCollectionInSharedContractMessage
{
get { return invalidCollectionInSharedContractMessage; }
}
internal bool ItemNameSetExplicit
{
get { return itemNameSetExplicit; }
}
internal XmlFormatCollectionWriterDelegate XmlFormatWriterDelegate
{
get { return xmlFormatWriterDelegate; }
set { xmlFormatWriterDelegate = value; }
}
internal XmlFormatCollectionReaderDelegate XmlFormatReaderDelegate
{
get { return xmlFormatReaderDelegate; }
set { xmlFormatReaderDelegate = value; }
}
internal XmlFormatGetOnlyCollectionReaderDelegate XmlFormatGetOnlyCollectionReaderDelegate
{
get { return xmlFormatGetOnlyCollectionReaderDelegate; }
set { xmlFormatGetOnlyCollectionReaderDelegate = value; }
}
}
DataContract GetSharedTypeContract(Type type)
{
if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false))
{
return this;
}
// ClassDataContract.IsNonAttributedTypeValidForSerialization does not need to be called here. It should
// never pass because it returns false for types that implement any of CollectionDataContract.KnownInterfaces
if (type.IsSerializable || type.IsDefined(Globals.TypeOfDataContractAttribute, false))
{
return new ClassDataContract(type);
}
return null;
}
internal static bool IsCollectionInterface(Type type)
{
if (type.IsGenericType)
type = type.GetGenericTypeDefinition();
return ((IList<Type>)KnownInterfaces).Contains(type);
}
internal static bool IsCollection(Type type)
{
Type itemType;
return IsCollection(type, out itemType);
}
internal static bool IsCollection(Type type, out Type itemType)
{
return IsCollectionHelper(type, out itemType, true /*constructorRequired*/);
}
internal static bool IsCollection(Type type, bool constructorRequired, bool skipIfReadOnlyContract)
{
Type itemType;
return IsCollectionHelper(type, out itemType, constructorRequired, skipIfReadOnlyContract);
}
static bool IsCollectionHelper(Type type, out Type itemType, bool constructorRequired, bool skipIfReadOnlyContract = false)
{
if (type.IsArray && DataContract.GetBuiltInDataContract(type) == null)
{
itemType = type.GetElementType();
return true;
}
DataContract dataContract;
return IsCollectionOrTryCreate(type, false /*tryCreate*/, out dataContract, out itemType, constructorRequired, skipIfReadOnlyContract);
}
internal static bool TryCreate(Type type, out DataContract dataContract)
{
Type itemType;
return IsCollectionOrTryCreate(type, true /*tryCreate*/, out dataContract, out itemType, true /*constructorRequired*/);
}
internal static bool TryCreateGetOnlyCollectionDataContract(Type type, out DataContract dataContract)
{
Type itemType;
if (type.IsArray)
{
dataContract = new CollectionDataContract(type);
return true;
}
else
{
return IsCollectionOrTryCreate(type, true /*tryCreate*/, out dataContract, out itemType, false /*constructorRequired*/);
}
}
internal static MethodInfo GetTargetMethodWithName(string name, Type type, Type interfaceType)
{
InterfaceMapping mapping = type.GetInterfaceMap(interfaceType);
for (int i = 0; i < mapping.TargetMethods.Length; i++)
{
if (mapping.InterfaceMethods[i].Name == name)
return mapping.InterfaceMethods[i];
}
return null;
}
static bool IsArraySegment(Type t)
{
return t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(ArraySegment<>));
}
[System.Diagnostics.CodeAnalysis.SuppressMessage(FxCop.Category.Globalization, FxCop.Rule.DoNotPassLiteralsAsLocalizedParameters, Justification = "Private code.")]
static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataContract dataContract, out Type itemType, bool constructorRequired, bool skipIfReadOnlyContract = false)
{
dataContract = null;
itemType = Globals.TypeOfObject;
if (DataContract.GetBuiltInDataContract(type) != null)
{
return HandleIfInvalidCollection(type, tryCreate, false/*hasCollectionDataContract*/, false/*isBaseTypeCollection*/,
SR.CollectionTypeCannotBeBuiltIn, null, ref dataContract);
}
MethodInfo addMethod, getEnumeratorMethod;
bool hasCollectionDataContract = IsCollectionDataContract(type);
bool isReadOnlyContract = false;
string serializationExceptionMessage = null, deserializationExceptionMessage = null;
Type baseType = type.BaseType;
bool isBaseTypeCollection = (baseType != null && baseType != Globals.TypeOfObject
&& baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri) ? IsCollection(baseType) : false;
// Avoid creating an invalid collection contract for Serializable types since we can create a ClassDataContract instead
bool createContractWithException = isBaseTypeCollection && !type.IsSerializable;
if (type.IsDefined(Globals.TypeOfDataContractAttribute, false))
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException,
SR.CollectionTypeCannotHaveDataContract, null, ref dataContract);
}
if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type) || IsArraySegment(type))
{
return false;
}
if (!Globals.TypeOfIEnumerable.IsAssignableFrom(type))
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException,
SR.CollectionTypeIsNotIEnumerable, null, ref dataContract);
}
if (type.IsInterface)
{
Type interfaceTypeToCheck = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
Type[] knownInterfaces = KnownInterfaces;
for (int i = 0; i < knownInterfaces.Length; i++)
{
if (knownInterfaces[i] == interfaceTypeToCheck)
{
addMethod = null;
if (type.IsGenericType)
{
Type[] genericArgs = type.GetGenericArguments();
if (interfaceTypeToCheck == Globals.TypeOfIDictionaryGeneric)
{
itemType = Globals.TypeOfKeyValue.MakeGenericType(genericArgs);
addMethod = type.GetMethod(Globals.AddMethodName);
getEnumeratorMethod = Globals.TypeOfIEnumerableGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(genericArgs)).GetMethod(Globals.GetEnumeratorMethodName);
}
else
{
itemType = genericArgs[0];
if (interfaceTypeToCheck == Globals.TypeOfICollectionGeneric || interfaceTypeToCheck == Globals.TypeOfIListGeneric)
{
addMethod = Globals.TypeOfICollectionGeneric.MakeGenericType(itemType).GetMethod(Globals.AddMethodName);
}
getEnumeratorMethod = Globals.TypeOfIEnumerableGeneric.MakeGenericType(itemType).GetMethod(Globals.GetEnumeratorMethodName);
}
}
else
{
if (interfaceTypeToCheck == Globals.TypeOfIDictionary)
{
itemType = typeof(KeyValue<object, object>);
addMethod = type.GetMethod(Globals.AddMethodName);
}
else
{
itemType = Globals.TypeOfObject;
if (interfaceTypeToCheck == Globals.TypeOfIList)
{
addMethod = Globals.TypeOfIList.GetMethod(Globals.AddMethodName);
}
}
getEnumeratorMethod = Globals.TypeOfIEnumerable.GetMethod(Globals.GetEnumeratorMethodName);
}
if (tryCreate)
dataContract = new CollectionDataContract(type, (CollectionKind)(i + 1), itemType, getEnumeratorMethod, addMethod, null/*defaultCtor*/);
return true;
}
}
}
ConstructorInfo defaultCtor = null;
if (!type.IsValueType)
{
defaultCtor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Globals.EmptyTypeArray, null);
if (defaultCtor == null && constructorRequired)
{
// All collection types could be considered read-only collections except collection types that are marked [Serializable].
// Collection types marked [Serializable] cannot be read-only collections for backward compatibility reasons.
// DataContract types and POCO types cannot be collection types, so they don't need to be factored in
if (type.IsSerializable)
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException,
SR.CollectionTypeDoesNotHaveDefaultCtor, null, ref dataContract);
}
else
{
isReadOnlyContract = true;
GetReadOnlyCollectionExceptionMessages(type, hasCollectionDataContract, SR.CollectionTypeDoesNotHaveDefaultCtor, null, out serializationExceptionMessage, out deserializationExceptionMessage);
}
}
}
Type knownInterfaceType = null;
CollectionKind kind = CollectionKind.None;
bool multipleDefinitions = false;
Type[] interfaceTypes = type.GetInterfaces();
foreach (Type interfaceType in interfaceTypes)
{
Type interfaceTypeToCheck = interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType;
Type[] knownInterfaces = KnownInterfaces;
for (int i = 0; i < knownInterfaces.Length; i++)
{
if (knownInterfaces[i] == interfaceTypeToCheck)
{
CollectionKind currentKind = (CollectionKind)(i + 1);
if (kind == CollectionKind.None || currentKind < kind)
{
kind = currentKind;
knownInterfaceType = interfaceType;
multipleDefinitions = false;
}
else if ((kind & currentKind) == currentKind)
multipleDefinitions = true;
break;
}
}
}
if (kind == CollectionKind.None)
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException,
SR.CollectionTypeIsNotIEnumerable, null, ref dataContract);
}
if (kind == CollectionKind.Enumerable || kind == CollectionKind.Collection || kind == CollectionKind.GenericEnumerable)
{
if (multipleDefinitions)
knownInterfaceType = Globals.TypeOfIEnumerable;
itemType = knownInterfaceType.IsGenericType ? knownInterfaceType.GetGenericArguments()[0] : Globals.TypeOfObject;
GetCollectionMethods(type, knownInterfaceType, new Type[] { itemType },
false /*addMethodOnInterface*/,
out getEnumeratorMethod, out addMethod);
if (addMethod == null)
{
// All collection types could be considered read-only collections except collection types that are marked [Serializable].
// Collection types marked [Serializable] cannot be read-only collections for backward compatibility reasons.
// DataContract types and POCO types cannot be collection types, so they don't need to be factored in.
if (type.IsSerializable || skipIfReadOnlyContract)
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException && !skipIfReadOnlyContract,
SR.CollectionTypeDoesNotHaveAddMethod, DataContract.GetClrTypeFullName(itemType), ref dataContract);
}
else
{
isReadOnlyContract = true;
GetReadOnlyCollectionExceptionMessages(type, hasCollectionDataContract, SR.CollectionTypeDoesNotHaveAddMethod, DataContract.GetClrTypeFullName(itemType), out serializationExceptionMessage, out deserializationExceptionMessage);
}
}
if (tryCreate)
{
dataContract = isReadOnlyContract ?
new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage) :
new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, addMethod, defaultCtor, !constructorRequired);
}
}
else
{
if (multipleDefinitions)
{
return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException,
SR.CollectionTypeHasMultipleDefinitionsOfInterface, KnownInterfaces[(int)kind - 1].Name, ref dataContract);
}
Type[] addMethodTypeArray = null;
switch (kind)
{
case CollectionKind.GenericDictionary:
addMethodTypeArray = knownInterfaceType.GetGenericArguments();
bool isOpenGeneric = knownInterfaceType.IsGenericTypeDefinition
|| (addMethodTypeArray[0].IsGenericParameter && addMethodTypeArray[1].IsGenericParameter);
itemType = isOpenGeneric ? Globals.TypeOfKeyValue : Globals.TypeOfKeyValue.MakeGenericType(addMethodTypeArray);
break;
case CollectionKind.Dictionary:
addMethodTypeArray = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
itemType = Globals.TypeOfKeyValue.MakeGenericType(addMethodTypeArray);
break;
case CollectionKind.GenericList:
case CollectionKind.GenericCollection:
addMethodTypeArray = knownInterfaceType.GetGenericArguments();
itemType = addMethodTypeArray[0];
break;
case CollectionKind.List:
itemType = Globals.TypeOfObject;
addMethodTypeArray = new Type[] { itemType };
break;
}
if (tryCreate)
{
GetCollectionMethods(type, knownInterfaceType, addMethodTypeArray,
true /*addMethodOnInterface*/,
out getEnumeratorMethod, out addMethod);
dataContract = isReadOnlyContract ?
new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage) :
new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, addMethod, defaultCtor, !constructorRequired);
}
}
return !(isReadOnlyContract && skipIfReadOnlyContract);
}
internal static bool IsCollectionDataContract(Type type)
{
return type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false);
}
static bool HandleIfInvalidCollection(Type type, bool tryCreate, bool hasCollectionDataContract, bool createContractWithException, string message, string param, ref DataContract dataContract)
{
if (hasCollectionDataContract)
{
if (tryCreate)
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(GetInvalidCollectionMessage(message, SR.GetString(SR.InvalidCollectionDataContract, DataContract.GetClrTypeFullName(type)), param)));
return true;
}
if (createContractWithException)
{
if (tryCreate)
dataContract = new CollectionDataContract(type, GetInvalidCollectionMessage(message, SR.GetString(SR.InvalidCollectionType, DataContract.GetClrTypeFullName(type)), param));
return true;
}
return false;
}
static void GetReadOnlyCollectionExceptionMessages(Type type, bool hasCollectionDataContract, string message, string param, out string serializationExceptionMessage, out string deserializationExceptionMessage)
{
serializationExceptionMessage = GetInvalidCollectionMessage(message, SR.GetString(hasCollectionDataContract ? SR.InvalidCollectionDataContract : SR.InvalidCollectionType, DataContract.GetClrTypeFullName(type)), param);
deserializationExceptionMessage = GetInvalidCollectionMessage(message, SR.GetString(SR.ReadOnlyCollectionDeserialization, DataContract.GetClrTypeFullName(type)), param);
}
static string GetInvalidCollectionMessage(string message, string nestedMessage, string param)
{
return (param == null) ? SR.GetString(message, nestedMessage) : SR.GetString(message, nestedMessage, param);
}
static void FindCollectionMethodsOnInterface(Type type, Type interfaceType, ref MethodInfo addMethod, ref MethodInfo getEnumeratorMethod)
{
InterfaceMapping mapping = type.GetInterfaceMap(interfaceType);
for (int i = 0; i < mapping.TargetMethods.Length; i++)
{
if (mapping.InterfaceMethods[i].Name == Globals.AddMethodName)
addMethod = mapping.InterfaceMethods[i];
else if (mapping.InterfaceMethods[i].Name == Globals.GetEnumeratorMethodName)
getEnumeratorMethod = mapping.InterfaceMethods[i];
}
}
static void GetCollectionMethods(Type type, Type interfaceType, Type[] addMethodTypeArray, bool addMethodOnInterface, out MethodInfo getEnumeratorMethod, out MethodInfo addMethod)
{
addMethod = getEnumeratorMethod = null;
if (addMethodOnInterface)
{
addMethod = type.GetMethod(Globals.AddMethodName, BindingFlags.Instance | BindingFlags.Public, null, addMethodTypeArray, null);
if (addMethod == null || addMethod.GetParameters()[0].ParameterType != addMethodTypeArray[0])
{
FindCollectionMethodsOnInterface(type, interfaceType, ref addMethod, ref getEnumeratorMethod);
if (addMethod == null)
{
Type[] parentInterfaceTypes = interfaceType.GetInterfaces();
foreach (Type parentInterfaceType in parentInterfaceTypes)
{
if (IsKnownInterface(parentInterfaceType))
{
FindCollectionMethodsOnInterface(type, parentInterfaceType, ref addMethod, ref getEnumeratorMethod);
if (addMethod == null)
{
break;
}
}
}
}
}
}
else
{
// GetMethod returns Add() method with parameter closest matching T in assignability/inheritance chain
addMethod = type.GetMethod(Globals.AddMethodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, addMethodTypeArray, null);
}
if (getEnumeratorMethod == null)
{
getEnumeratorMethod = type.GetMethod(Globals.GetEnumeratorMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
if (getEnumeratorMethod == null || !Globals.TypeOfIEnumerator.IsAssignableFrom(getEnumeratorMethod.ReturnType))
{
Type ienumerableInterface = interfaceType.GetInterface("System.Collections.Generic.IEnumerable*");
if (ienumerableInterface == null)
ienumerableInterface = Globals.TypeOfIEnumerable;
getEnumeratorMethod = GetTargetMethodWithName(Globals.GetEnumeratorMethodName, type, ienumerableInterface);
}
}
}
static bool IsKnownInterface(Type type)
{
Type typeToCheck = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
foreach (Type knownInterfaceType in KnownInterfaces)
{
if (typeToCheck == knownInterfaceType)
{
return true;
}
}
return false;
}
[Fx.Tag.SecurityNote(Critical = "Sets critical properties on CollectionDataContract .",
Safe = "Called during schema import/code generation.")]
[SecuritySafeCritical]
internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary<DataContract, DataContract> boundContracts)
{
DataContract boundContract;
if (boundContracts.TryGetValue(this, out boundContract))
return boundContract;
CollectionDataContract boundCollectionContract = new CollectionDataContract(Kind);
boundContracts.Add(this, boundCollectionContract);
boundCollectionContract.ItemContract = this.ItemContract.BindGenericParameters(paramContracts, boundContracts);
boundCollectionContract.IsItemTypeNullable = !boundCollectionContract.ItemContract.IsValueType;
boundCollectionContract.ItemName = ItemNameSetExplicit ? this.ItemName : boundCollectionContract.ItemContract.StableName.Name;
boundCollectionContract.KeyName = this.KeyName;
boundCollectionContract.ValueName = this.ValueName;
boundCollectionContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(this.StableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(this.UnderlyingType), paramContracts)),
IsCollectionDataContract(UnderlyingType) ? this.StableName.Namespace : DataContract.GetCollectionNamespace(boundCollectionContract.ItemContract.StableName.Namespace));
return boundCollectionContract;
}
internal override DataContract GetValidContract(SerializationMode mode)
{
if (mode == SerializationMode.SharedType)
{
if (SharedTypeContract == null)
DataContract.ThrowTypeNotSerializable(UnderlyingType);
return SharedTypeContract;
}
ThrowIfInvalid();
return this;
}
void ThrowIfInvalid()
{
if (InvalidCollectionInSharedContractMessage != null)
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(InvalidCollectionInSharedContractMessage));
}
internal override DataContract GetValidContract()
{
if (this.IsConstructorCheckRequired)
{
CheckConstructor();
}
return this;
}
[Fx.Tag.SecurityNote(Critical = "Sets the critical IsConstructorCheckRequired property on CollectionDataContract.",
Safe = "Does not leak anything.")]
[SecuritySafeCritical]
void CheckConstructor()
{
if (this.Constructor == null)
{
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.CollectionTypeDoesNotHaveDefaultCtor, DataContract.GetClrTypeFullName(this.UnderlyingType))));
}
else
{
this.IsConstructorCheckRequired = false;
}
}
internal override bool IsValidContract(SerializationMode mode)
{
if (mode == SerializationMode.SharedType)
return (SharedTypeContract != null);
return (InvalidCollectionInSharedContractMessage == null);
}
#if !NO_DYNAMIC_CODEGEN
[Fx.Tag.SecurityNote(Miscellaneous =
"RequiresReview - Calculates whether this collection 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)
{
if (!IsTypeVisible(UnderlyingType))
{
if (securityException != null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SecurityException(SR.GetString(
SR.PartialTrustCollectionContractTypeNotPublic,
DataContract.GetClrTypeFullName(UnderlyingType)),
securityException));
}
return true;
}
if (ItemType != null && !IsTypeVisible(ItemType))
{
if (securityException != null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SecurityException(SR.GetString(
SR.PartialTrustCollectionContractTypeNotPublic,
DataContract.GetClrTypeFullName(ItemType)),
securityException));
}
return true;
}
if (ConstructorRequiresMemberAccess(Constructor))
{
if (securityException != null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SecurityException(SR.GetString(
SR.PartialTrustCollectionContractNoPublicConstructor,
DataContract.GetClrTypeFullName(UnderlyingType)),
securityException));
}
return true;
}
if (MethodRequiresMemberAccess(this.AddMethod))
{
if (securityException != null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SecurityException(SR.GetString(
SR.PartialTrustCollectionContractAddMethodNotPublic,
DataContract.GetClrTypeFullName(UnderlyingType),
this.AddMethod.Name),
securityException));
}
return true;
}
return false;
}
[Fx.Tag.SecurityNote(Miscellaneous =
"RequiresReview - Calculates whether this collection 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)
{
if (!IsTypeVisible(UnderlyingType))
{
if (securityException != null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SecurityException(SR.GetString(
SR.PartialTrustCollectionContractTypeNotPublic,
DataContract.GetClrTypeFullName(UnderlyingType)),
securityException));
}
return true;
}
if (ItemType != null && !IsTypeVisible(ItemType))
{
if (securityException != null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SecurityException(SR.GetString(
SR.PartialTrustCollectionContractTypeNotPublic,
DataContract.GetClrTypeFullName(ItemType)),
securityException));
}
return true;
}
return false;
}
#endif
internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
{
if (IsEqualOrChecked(other, checkedContracts))
return true;
if (base.Equals(other, checkedContracts))
{
CollectionDataContract dataContract = other as CollectionDataContract;
if (dataContract != null)
{
bool thisItemTypeIsNullable = (ItemContract == null) ? false : !ItemContract.IsValueType;
bool otherItemTypeIsNullable = (dataContract.ItemContract == null) ? false : !dataContract.ItemContract.IsValueType;
return ItemName == dataContract.ItemName &&
(IsItemTypeNullable || thisItemTypeIsNullable) == (dataContract.IsItemTypeNullable || otherItemTypeIsNullable) &&
ItemContract.Equals(dataContract.ItemContract, checkedContracts);
}
}
return false;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context)
{
// IsGetOnlyCollection value has already been used to create current collectiondatacontract, value can now be reset.
context.IsGetOnlyCollection = false;
XmlFormatWriterDelegate(xmlWriter, obj, context, this);
}
public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
{
xmlReader.Read();
object o = null;
if (context.IsGetOnlyCollection)
{
// IsGetOnlyCollection value has already been used to create current collectiondatacontract, value can now be reset.
context.IsGetOnlyCollection = false;
XmlFormatGetOnlyCollectionReaderDelegate(xmlReader, context, CollectionItemName, Namespace, this);
}
else
{
o = XmlFormatReaderDelegate(xmlReader, context, CollectionItemName, Namespace, this);
}
xmlReader.ReadEndElement();
return o;
}
public class DictionaryEnumerator : IEnumerator<KeyValue<object, object>>
{
IDictionaryEnumerator enumerator;
public DictionaryEnumerator(IDictionaryEnumerator enumerator)
{
this.enumerator = enumerator;
}
public void Dispose()
{
}
public bool MoveNext()
{
return enumerator.MoveNext();
}
public KeyValue<object, object> Current
{
get { return new KeyValue<object, object>(enumerator.Key, enumerator.Value); }
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public void Reset()
{
enumerator.Reset();
}
}
public class GenericDictionaryEnumerator<K, V> : IEnumerator<KeyValue<K, V>>
{
IEnumerator<KeyValuePair<K, V>> enumerator;
public GenericDictionaryEnumerator(IEnumerator<KeyValuePair<K, V>> enumerator)
{
this.enumerator = enumerator;
}
public void Dispose()
{
}
public bool MoveNext()
{
return enumerator.MoveNext();
}
public KeyValue<K, V> Current
{
get
{
KeyValuePair<K, V> current = enumerator.Current;
return new KeyValue<K, V>(current.Key, current.Value);
}
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public void Reset()
{
enumerator.Reset();
}
}
}
}