|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.DataContracts;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace System.Runtime.Serialization
{
internal abstract class ReflectionReader
{
private delegate object? CollectionReadItemDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, CollectionDataContract collectionContract, Type itemType, string itemName, string itemNs);
private delegate object CollectionSetItemDelegate(object resultCollection, object? collectionItem, int itemIndex);
private static MethodInfo? s_getCollectionSetItemDelegateMethod;
private static readonly MethodInfo s_objectToKeyValuePairGetKey = typeof(ReflectionReader).GetMethod(nameof(ObjectToKeyValuePairGetKey), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)!;
private static readonly MethodInfo s_objectToKeyValuePairGetValue = typeof(ReflectionReader).GetMethod(nameof(ObjectToKeyValuePairGetValue), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)!;
private static readonly Type[] s_arrayConstructorParameters = new Type[] { Globals.TypeOfInt };
private static readonly object[] s_arrayConstructorArguments = new object[] { 32 };
private static MethodInfo CollectionSetItemDelegateMethod =>
s_getCollectionSetItemDelegateMethod ??= typeof(ReflectionReader).GetMethod(nameof(GetCollectionSetItemDelegate), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)!;
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
public object ReflectionReadClass(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context, XmlDictionaryString[]? memberNames, XmlDictionaryString[]? memberNamespaces, ClassDataContract classContract)
{
Debug.Assert(context != null);
object obj = CreateObject(classContract);
context.AddNewObject(obj);
InvokeOnDeserializing(context, classContract, obj);
if (classContract.IsISerializable)
{
obj = ReadISerializable(xmlReader, context, classContract);
}
else
{
Debug.Assert(memberNames != null);
ReflectionReadMembers(xmlReader, context, memberNames, memberNamespaces, classContract, ref obj);
}
#pragma warning disable SYSLIB0050 // IObjectReference is obsolete
if (obj is IObjectReference objectReference)
{
obj = context.GetRealObject(objectReference, context.GetObjectId());
}
#pragma warning restore SYSLIB0050
obj = ResolveAdapterObject(obj);
InvokeDeserializationCallback(obj);
InvokeOnDeserialized(context, classContract, obj);
return obj;
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
public void ReflectionReadGetOnlyCollection(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString collectionItemName, XmlDictionaryString collectionItemNamespace, CollectionDataContract collectionContract)
{
object? resultCollection = context.GetCollectionMember();
if (ReflectionReadSpecialCollection(xmlReader, context, collectionContract, resultCollection))
{
return;
}
if (xmlReader.IsStartElement(collectionItemName, collectionItemNamespace))
{
if (resultCollection == null)
{
XmlObjectSerializerReadContext.ThrowNullValueReturnedForGetOnlyCollectionException(collectionContract.UnderlyingType);
}
bool isReadOnlyCollection = true;
ReadCollectionItems(xmlReader, context, collectionItemName, collectionItemNamespace, collectionContract, resultCollection, isReadOnlyCollection);
}
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
public object ReflectionReadCollection(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString collectionItemName, XmlDictionaryString collectionItemNamespace, CollectionDataContract collectionContract)
{
return ReflectionReadCollectionCore(xmlReader, context, collectionItemName, collectionItemNamespace, collectionContract);
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
private object ReflectionReadCollectionCore(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString collectionItemName, XmlDictionaryString collectionItemNamespace, CollectionDataContract collectionContract)
{
bool isArray = (collectionContract.Kind == CollectionKind.Array);
int arraySize = context.GetArraySize();
object? resultArray;
if (isArray && ReflectionTryReadPrimitiveArray(xmlReader, context, collectionItemName, collectionItemNamespace, collectionContract.ItemType, arraySize, out resultArray))
{
return resultArray;
}
object resultCollection = ReflectionCreateCollection(collectionContract);
context.AddNewObject(resultCollection);
context.IncrementItemCount(1);
if (!ReflectionReadSpecialCollection(xmlReader, context, collectionContract, resultCollection))
{
bool isReadOnlyCollection = false;
resultCollection = ReadCollectionItems(xmlReader, context, collectionItemName, collectionItemNamespace, collectionContract, resultCollection, isReadOnlyCollection);
}
return resultCollection;
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
private CollectionReadItemDelegate GetCollectionReadItemDelegate(CollectionDataContract collectionContract)
{
CollectionReadItemDelegate collectionReadItemDelegate;
if (collectionContract.Kind == CollectionKind.Dictionary || collectionContract.Kind == CollectionKind.GenericDictionary)
{
collectionReadItemDelegate = GetReadDictionaryItemDelegate;
}
else
{
collectionReadItemDelegate = GetReflectionReadValueDelegate(collectionContract.ItemType);
}
return collectionReadItemDelegate;
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
object? GetReadDictionaryItemDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, CollectionDataContract collectionContract, Type itemType, string itemName, string itemNs)
{
return ReflectionReadDictionaryItem(xmlReader, context, collectionContract);
};
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
private object ReadCollectionItems(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString collectionItemName, XmlDictionaryString collectionItemNamespace, CollectionDataContract collectionContract, object resultCollection, bool isReadOnlyCollection)
{
string itemName = GetCollectionContractItemName(collectionContract);
string itemNs = GetCollectionContractNamespace(collectionContract);
Type itemType = collectionContract.ItemType;
CollectionReadItemDelegate collectionReadItemDelegate = GetCollectionReadItemDelegate(collectionContract);
MethodInfo getCollectionSetItemDelegateMethod = CollectionSetItemDelegateMethod.MakeGenericMethod(itemType);
CollectionSetItemDelegate collectionSetItemDelegate = (CollectionSetItemDelegate)getCollectionSetItemDelegateMethod.Invoke(null, new object[] { collectionContract, resultCollection, isReadOnlyCollection })!;
int index = 0;
while (true)
{
if (xmlReader.IsStartElement(collectionItemName, collectionItemNamespace))
{
object? collectionItem = collectionReadItemDelegate(xmlReader, context, collectionContract, itemType, itemName, itemNs);
resultCollection = collectionSetItemDelegate(resultCollection, collectionItem, index);
index++;
}
else
{
if (xmlReader.NodeType == XmlNodeType.EndElement)
{
break;
}
if (!xmlReader.IsStartElement())
{
throw XmlObjectSerializerReadContext.CreateUnexpectedStateException(XmlNodeType.Element, xmlReader);
}
context.SkipUnknownElement(xmlReader);
}
}
context.IncrementItemCount(index);
if (!isReadOnlyCollection && IsArrayLikeCollection(collectionContract))
{
MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod(itemType);
resultCollection = trimArraySizeMethod.Invoke(null, new object[] { resultCollection, index })!;
}
return resultCollection;
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
protected abstract void ReflectionReadMembers(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString[] memberNames, XmlDictionaryString[]? memberNamespaces, ClassDataContract classContract, ref object obj);
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
protected abstract object? ReflectionReadDictionaryItem(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, CollectionDataContract collectionContract);
protected abstract string GetCollectionContractItemName(CollectionDataContract collectionContract);
protected abstract string GetCollectionContractNamespace(CollectionDataContract collectionContract);
protected abstract string GetClassContractNamespace(ClassDataContract classContract);
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
protected virtual bool ReflectionReadSpecialCollection(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, CollectionDataContract collectionContract, object? resultCollection)
{
return false;
}
protected static int ReflectionGetMembers(ClassDataContract classContract, DataMember[] members)
{
int memberCount = (classContract.BaseClassContract == null) ? 0 : ReflectionGetMembers(classContract.BaseClassContract, members);
int childElementIndex = memberCount;
for (int i = 0; i < classContract.Members!.Count; i++, memberCount++)
{
members[childElementIndex + i] = classContract.Members[i];
}
return memberCount;
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
protected void ReflectionReadMember(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, ClassDataContract classContract, ref object obj, int memberIndex, DataMember[] members)
{
DataMember dataMember = members[memberIndex];
Debug.Assert(dataMember != null);
if (dataMember.IsGetOnlyCollection)
{
var memberValue = ReflectionGetMemberValue(obj, dataMember);
context.StoreCollectionMemberInfo(memberValue);
ReflectionReadValue(xmlReader, context, dataMember, GetClassContractNamespace(classContract));
}
else
{
context.ResetCollectionMemberInfo();
var value = ReflectionReadValue(xmlReader, context, dataMember, classContract.XmlName.Namespace);
MemberInfo memberInfo = dataMember.MemberInfo;
Debug.Assert(memberInfo != null);
ReflectionSetMemberValue(ref obj, value, dataMember);
}
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
protected object? ReflectionReadValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, Type type, string name, string ns, PrimitiveDataContract? primitiveContractForOriginalType = null)
{
object? value;
int nullables = 0;
while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable)
{
nullables++;
type = type.GetGenericArguments()[0];
}
PrimitiveDataContract? primitiveContract = nullables != 0 ?
PrimitiveDataContract.GetPrimitiveDataContract(type)
: (primitiveContractForOriginalType ?? PrimitiveDataContract.GetPrimitiveDataContract(type));
if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType)
{
value = ReadItemOfPrimitiveType(xmlReader, context, type, name, ns, primitiveContract, nullables);
}
else
{
value = ReflectionInternalDeserialize(xmlReader, context, null/*collectionContract*/, type, name, ns);
}
return value;
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
private object? ReadItemOfPrimitiveType(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, Type type, string name, string ns, PrimitiveDataContract? primitiveContract, int nullables)
{
object? value;
context.ReadAttributes(xmlReader);
string objectId = context.ReadIfNullOrRef(xmlReader, type, DataContract.IsTypeSerializable(type));
bool typeIsValueType = type.IsValueType;
if (objectId != null)
{
if (objectId.Length == 0)
{
objectId = context.GetObjectId();
if (!string.IsNullOrEmpty(objectId) && typeIsValueType)
{
throw new SerializationException(SR.Format(SR.ValueTypeCannotHaveId, DataContract.GetClrTypeFullName(type)));
}
if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject)
{
value = primitiveContract.ReadXmlValue(xmlReader, context);
}
else
{
value = ReflectionInternalDeserialize(xmlReader, context, null/*collectionContract*/, type, name, ns);
}
}
else
{
if (typeIsValueType)
{
throw new SerializationException(SR.Format(SR.ValueTypeCannotHaveRef, DataContract.GetClrTypeFullName(type)));
}
else
{
value = context.GetExistingObject(objectId, type, name, ns);
}
}
}
else
{
if (typeIsValueType && nullables == 0)
{
throw new SerializationException(SR.Format(SR.ValueTypeCannotBeNull, DataContract.GetClrTypeFullName(type)));
}
else
{
value = null;
}
}
return value;
}
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
private static object ReadISerializable(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, ClassDataContract classContract)
{
object obj;
SerializationInfo serializationInfo = context.ReadSerializationInfo(xmlReader, classContract.UnderlyingType);
StreamingContext streamingContext = context.GetStreamingContext();
ConstructorInfo iSerializableConstructor = classContract.GetISerializableConstructor()!;
obj = iSerializableConstructor.Invoke(new object[] { serializationInfo, streamingContext });
return obj;
}
// This method is a perf optimization for collections. The original method is ReflectionReadValue.
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
private CollectionReadItemDelegate GetReflectionReadValueDelegate(Type type)
{
int nullables = 0;
while (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfNullable)
{
nullables++;
type = type.GetGenericArguments()[0];
}
PrimitiveDataContract? primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);
if ((primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject) || nullables != 0 || type.IsValueType)
{
return GetReadItemOfPrimitiveTypeDelegate;
}
else
{
return ReflectionInternalDeserialize;
}
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
object? GetReadItemOfPrimitiveTypeDelegate(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, CollectionDataContract collectionContract, Type itemType, string itemName, string itemNs)
{
return ReadItemOfPrimitiveType(xmlReader, context, itemType, itemName, itemNs, primitiveContract, nullables);
};
}
private static object? ReflectionGetMemberValue(object obj, DataMember dataMember)
{
return dataMember.Getter(obj);
}
private static void ReflectionSetMemberValue(ref object obj, object? memberValue, DataMember dataMember)
{
dataMember.Setter(ref obj, memberValue);
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
private object? ReflectionReadValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, DataMember dataMember, string ns)
{
Type type = dataMember.MemberType;
string name = dataMember.Name;
return ReflectionReadValue(xmlReader, context, type, name, ns, dataMember.MemberPrimitiveContract);
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
private object? ReflectionInternalDeserialize(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, CollectionDataContract? collectionContract, Type type, string name, string ns)
{
return context.InternalDeserialize(xmlReader, DataContract.GetId(type.TypeHandle), type.TypeHandle, name, ns);
}
private static void InvokeOnDeserializing(XmlObjectSerializerReadContext context, ClassDataContract classContract, object obj)
{
if (classContract.BaseClassContract != null)
InvokeOnDeserializing(context, classContract.BaseClassContract, obj);
if (classContract.OnDeserializing != null)
{
var contextArg = context.GetStreamingContext();
classContract.OnDeserializing.Invoke(obj, new object[] { contextArg });
}
}
private static void InvokeOnDeserialized(XmlObjectSerializerReadContext context, ClassDataContract classContract, object obj)
{
if (classContract.BaseClassContract != null)
InvokeOnDeserialized(context, classContract.BaseClassContract, obj);
if (classContract.OnDeserialized != null)
{
var contextArg = context.GetStreamingContext();
classContract.OnDeserialized.Invoke(obj, new object[] { contextArg });
}
}
private static void InvokeDeserializationCallback(object obj)
{
var deserializationCallbackObject = obj as IDeserializationCallback;
deserializationCallbackObject?.OnDeserialization(null);
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
private static object CreateObject(ClassDataContract classContract)
{
object? obj;
if (!classContract.CreateNewInstanceViaDefaultConstructor(out obj))
{
Type classType = classContract.UnderlyingType;
obj = XmlFormatReaderGenerator.UnsafeGetUninitializedObject(classType);
}
return obj;
}
private static object ResolveAdapterObject(object obj)
{
Type objType = obj.GetType();
if (objType == Globals.TypeOfDateTimeOffsetAdapter)
{
obj = DateTimeOffsetAdapter.GetDateTimeOffset((DateTimeOffsetAdapter)obj);
}
else if (objType == Globals.TypeOfMemoryStreamAdapter)
{
obj = MemoryStreamAdapter.GetMemoryStream((MemoryStreamAdapter)obj);
}
return obj;
}
private static bool IsArrayLikeInterface(CollectionDataContract collectionContract)
{
if (collectionContract.UnderlyingType.IsInterface)
{
switch (collectionContract.Kind)
{
case CollectionKind.Collection:
case CollectionKind.GenericCollection:
case CollectionKind.Enumerable:
case CollectionKind.GenericEnumerable:
case CollectionKind.List:
case CollectionKind.GenericList:
return true;
}
}
return false;
}
private static bool IsArrayLikeCollection(CollectionDataContract collectionContract)
{
return collectionContract.Kind == CollectionKind.Array || IsArrayLikeInterface(collectionContract);
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
private static object ReflectionCreateCollection(CollectionDataContract collectionContract)
{
if (IsArrayLikeCollection(collectionContract))
{
Type arrayType = collectionContract.ItemType.MakeArrayType();
var ci = arrayType.GetConstructor(s_arrayConstructorParameters)!;
var newArray = ci.Invoke(s_arrayConstructorArguments);
return newArray;
}
else if (collectionContract.Kind == CollectionKind.GenericDictionary && collectionContract.UnderlyingType.IsInterface)
{
Type type = Globals.TypeOfDictionaryGeneric.MakeGenericType(collectionContract.ItemType.GetGenericArguments());
ConstructorInfo ci = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, Type.EmptyTypes)!;
object newGenericDict = ci.Invoke(Array.Empty<object>());
return newGenericDict;
}
else
{
if (collectionContract.UnderlyingType.IsValueType)
{
object newValueObject = Activator.CreateInstance(collectionContract.UnderlyingType)!;
return newValueObject;
}
else if (collectionContract.UnderlyingType == Globals.TypeOfIDictionary)
{
object newGenericDict = new Dictionary<object, object>();
return newGenericDict;
}
else
{
ConstructorInfo ci = collectionContract.Constructor!;
object newCollection = ci.Invoke(Array.Empty<object>());
return newCollection;
}
}
}
private static object? ObjectToKeyValuePairGetKey<K, V>(object o)
{
return ((KeyValue<K, V>)o).Key;
}
private static object? ObjectToKeyValuePairGetValue<K, V>(object o)
{
return ((KeyValue<K, V>)o).Value;
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
private static CollectionSetItemDelegate GetCollectionSetItemDelegate<T>(CollectionDataContract collectionContract, object resultCollectionObject, bool isReadOnlyCollection)
{
if (isReadOnlyCollection && collectionContract.Kind == CollectionKind.Array)
{
int arraySize = ((Array)resultCollectionObject).Length;
return (resultCollection, collectionItem, index) =>
{
if (index == arraySize)
{
XmlObjectSerializerReadContext.ThrowArrayExceededSizeException(arraySize, collectionContract.UnderlyingType);
}
((T[])resultCollection)[index] = (T)collectionItem!;
return resultCollection;
};
}
else if (!isReadOnlyCollection && IsArrayLikeCollection(collectionContract))
{
return (resultCollection, collectionItem, index) =>
{
resultCollection = XmlObjectSerializerReadContext.EnsureArraySize((T[])resultCollection, index);
((T[])resultCollection)[index] = (T)collectionItem!;
return resultCollection;
};
}
else if (collectionContract.Kind == CollectionKind.GenericDictionary || collectionContract.Kind == CollectionKind.Dictionary)
{
Type keyType = collectionContract.ItemType.GenericTypeArguments[0];
Type valueType = collectionContract.ItemType.GenericTypeArguments[1];
Func<object, object?> objectToKeyValuePairGetKey = MakeGenericMethod(s_objectToKeyValuePairGetKey, keyType, valueType).CreateDelegate<Func<object, object?>>();
Func<object, object?> objectToKeyValuePairGetValue = MakeGenericMethod(s_objectToKeyValuePairGetValue, keyType, valueType).CreateDelegate<Func<object, object?>>();
if (collectionContract.Kind == CollectionKind.GenericDictionary)
{
return (resultCollection, collectionItem, index) =>
{
object? key = objectToKeyValuePairGetKey(collectionItem!);
object? value = objectToKeyValuePairGetValue(collectionItem!);
collectionContract.AddMethod!.Invoke(resultCollection, new object?[] { key, value });
return resultCollection;
};
}
else
{
return (resultCollection, collectionItem, index) =>
{
object? key = objectToKeyValuePairGetKey(collectionItem!);
object? value = objectToKeyValuePairGetValue(collectionItem!);
IDictionary dict = (IDictionary)resultCollection;
dict.Add(key!, value);
return resultCollection;
};
}
}
else
{
Type collectionType = resultCollectionObject.GetType();
Type genericCollectionType = typeof(ICollection<T>);
Type typeIList = Globals.TypeOfIList;
if (genericCollectionType.IsAssignableFrom(collectionType))
{
return (resultCollection, collectionItem, index) =>
{
((ICollection<T>)resultCollection).Add((T)collectionItem!);
return resultCollection;
};
}
else if (typeIList.IsAssignableFrom(collectionType))
{
return (resultCollection, collectionItem, index) =>
{
((IList)resultCollection).Add(collectionItem);
return resultCollection;
};
}
else
{
MethodInfo? addMethod = collectionContract.AddMethod;
if (addMethod == null)
{
throw new InvalidDataContractException(SR.Format(SR.CollectionMustHaveAddMethod, DataContract.GetClrTypeFullName(collectionContract.UnderlyingType)));
}
return (resultCollection, collectionItem, index) =>
{
addMethod.Invoke(resultCollection, new object?[] { collectionItem });
return resultCollection;
};
}
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod",
Justification = "The call to MakeGenericMethod is safe due to the fact that ObjectToKeyValuePairGetKey and ObjectToKeyValuePairGetValue are not annotated.")]
static MethodInfo MakeGenericMethod(MethodInfo method, Type keyType, Type valueType) => method.MakeGenericMethod(keyType, valueType);
}
[RequiresDynamicCode(DataContract.SerializerAOTWarning)]
[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)]
private static bool ReflectionTryReadPrimitiveArray(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context, XmlDictionaryString collectionItemName, XmlDictionaryString collectionItemNamespace, Type itemType, int arraySize, [NotNullWhen(true)] out object? resultArray)
{
resultArray = null;
PrimitiveDataContract? primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType);
if (primitiveContract == null)
return false;
switch (Type.GetTypeCode(itemType))
{
case TypeCode.Boolean:
{
bool[]? boolArray;
if (xmlReader.TryReadBooleanArray(context, collectionItemName, collectionItemNamespace, arraySize, out boolArray))
{
resultArray = boolArray;
}
}
break;
case TypeCode.DateTime:
{
DateTime[]? dateTimeArray;
if (xmlReader.TryReadDateTimeArray(context, collectionItemName, collectionItemNamespace, arraySize, out dateTimeArray))
{
resultArray = dateTimeArray;
}
}
break;
case TypeCode.Decimal:
{
decimal[]? decimalArray;
if (xmlReader.TryReadDecimalArray(context, collectionItemName, collectionItemNamespace, arraySize, out decimalArray))
{
resultArray = decimalArray;
}
}
break;
case TypeCode.Int32:
{
int[]? intArray;
if (xmlReader.TryReadInt32Array(context, collectionItemName, collectionItemNamespace, arraySize, out intArray))
{
resultArray = intArray;
}
}
break;
case TypeCode.Int64:
{
long[]? longArray;
if (xmlReader.TryReadInt64Array(context, collectionItemName, collectionItemNamespace, arraySize, out longArray))
{
resultArray = longArray;
}
}
break;
case TypeCode.Single:
{
float[]? floatArray;
if (xmlReader.TryReadSingleArray(context, collectionItemName, collectionItemNamespace, arraySize, out floatArray))
{
resultArray = floatArray;
}
}
break;
case TypeCode.Double:
{
double[]? doubleArray;
if (xmlReader.TryReadDoubleArray(context, collectionItemName, collectionItemNamespace, arraySize, out doubleArray))
{
resultArray = doubleArray;
}
}
break;
default:
return false;
}
return resultArray != null;
}
}
}
|