|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Formats.Nrbf;
using System.Private.Windows.Core.Resources;
using System.Reflection;
using System.Runtime.Serialization;
namespace System.Private.Windows.Core.BinaryFormat;
#pragma warning disable SYSLIB0050 // Type or member is obsolete
internal sealed class PendingSerializationInfo
{
internal SerializationRecordId ObjectId { get; }
private readonly ISerializationSurrogate? _surrogate;
private readonly SerializationInfo _info;
internal PendingSerializationInfo(
SerializationRecordId objectId,
SerializationInfo info,
ISerializationSurrogate? surrogate)
{
ObjectId = objectId;
_surrogate = surrogate;
_info = info;
}
[RequiresUnreferencedCode("We can't guarantee that the ctor will be present, as the type is not known up-front.")]
internal void Populate(IDictionary<SerializationRecordId, object> objects, StreamingContext context)
{
object @object = objects[ObjectId];
Type type = @object.GetType();
if (_surrogate is not null)
{
object populated = _surrogate.SetObjectData(@object, _info, context, selector: null);
if (populated is null)
{
// Sort of odd to allow returning null to ignore setting the returned value back,
// but that is the way this worked in the BinaryFormatter.
return;
}
// Don't use == on reference types as we are dependent on the instance in the objects
// dictionary never changing. Value types can be modified but this is ok as any usages
// of this object will have a pending fixup that will reapply the value.
//
// BinaryFormatter would allow this to change as long as you didn't wrap the surrogate
// in FormaterServices.GetSurrogateForCyclicalReference. We break here on value types
// as they can never be observed in an unfinished state.
if (!type.IsValueType && !ReferenceEquals(populated, @object))
{
throw new SerializationException(SR.Serialization_Surrogates);
}
objects[ObjectId] = populated;
return;
}
ConstructorInfo constructor = GetDeserializationConstructor(type);
constructor.Invoke(@object, [_info, context]);
}
private static ConstructorInfo GetDeserializationConstructor(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type)
{
foreach (ConstructorInfo constructor in type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
ParameterInfo[] parameters = constructor.GetParameters();
if (parameters.Length == 2
&& parameters[0].ParameterType == typeof(SerializationInfo)
&& parameters[1].ParameterType == typeof(StreamingContext))
{
return constructor;
}
}
throw new SerializationException(string.Format(SR.Serialization_MissingCtor, type.FullName));
}
}
#pragma warning restore SYSLIB0050 // Type or member is obsolete
|