| File: System\Runtime\Serialization\DataMember.cs | Web Access |
| Project: src\runtime\src\libraries\System.Private.DataContractSerialization\src\System.Private.DataContractSerialization.csproj (System.Private.DataContractSerialization) |
// 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.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace System.Runtime.Serialization.DataContracts { public sealed class DataMember { private readonly CriticalHelper _helper; internal DataMember(MemberInfo memberInfo) { _helper = new CriticalHelper(memberInfo); } internal DataMember(DataContract memberTypeContract, string name, bool isNullable, bool isRequired, bool emitDefaultValue, long order) { _helper = new CriticalHelper(memberTypeContract, name, isNullable, isRequired, emitDefaultValue, order); } internal MemberInfo MemberInfo => _helper.MemberInfo; public string Name { get => _helper.Name; internal set => _helper.Name = value; } public long Order { get => _helper.Order; internal set => _helper.Order = value; } public bool IsRequired { get => _helper.IsRequired; internal set => _helper.IsRequired = value; } public bool EmitDefaultValue { get => _helper.EmitDefaultValue; internal set => _helper.EmitDefaultValue = value; } public bool IsNullable { get => _helper.IsNullable; internal set => _helper.IsNullable = value; } internal bool IsGetOnlyCollection { get => _helper.IsGetOnlyCollection; set => _helper.IsGetOnlyCollection = value; } internal Type MemberType => _helper.MemberType; public DataContract MemberTypeContract { [RequiresDynamicCode(DataContract.SerializerAOTWarning)] [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _helper.MemberTypeContract; } internal PrimitiveDataContract? MemberPrimitiveContract { [RequiresDynamicCode(DataContract.SerializerAOTWarning)] [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _helper.MemberPrimitiveContract; } internal bool HasConflictingNameAndType { get => _helper.HasConflictingNameAndType; set => _helper.HasConflictingNameAndType = value; } internal DataMember? ConflictingMember { get => _helper.ConflictingMember; set => _helper.ConflictingMember = value; } internal FastInvokerBuilder.Getter Getter => field ??= FastInvokerBuilder.CreateGetter(MemberInfo); internal FastInvokerBuilder.Setter Setter => field ??= FastInvokerBuilder.CreateSetter(MemberInfo); private sealed class CriticalHelper { private DataContract? _memberTypeContract; private string _name = null!; // Name is always initialized right after construction private long _order; private bool _isRequired; private bool _emitDefaultValue; private bool _isNullable; private bool _isGetOnlyCollection; private readonly MemberInfo _memberInfo; private Type? _memberType; private bool _hasConflictingNameAndType; private DataMember? _conflictingMember; internal CriticalHelper(MemberInfo memberInfo) { _emitDefaultValue = Globals.DefaultEmitDefaultValue; _memberInfo = memberInfo; _memberPrimitiveContract = PrimitiveDataContract.NullContract; } internal CriticalHelper(DataContract memberTypeContract, string name, bool isNullable, bool isRequired, bool emitDefaultValue, long order) { _memberTypeContract = memberTypeContract; _name = name; _isNullable = isNullable; _isRequired = isRequired; _emitDefaultValue = emitDefaultValue; _order = order; _memberInfo = memberTypeContract.UnderlyingType; } internal MemberInfo MemberInfo => _memberInfo; internal string Name { get => _name; set => _name = value; } internal long Order { get => _order; set => _order = value; } internal bool IsRequired { get => _isRequired; set => _isRequired = value; } internal bool EmitDefaultValue { get => _emitDefaultValue; set => _emitDefaultValue = value; } internal bool IsNullable { get => _isNullable; set => _isNullable = value; } internal bool IsGetOnlyCollection { get => _isGetOnlyCollection; set => _isGetOnlyCollection = value; } internal Type MemberType { get { if (_memberType == null) { if (MemberInfo is FieldInfo fieldInfo) _memberType = fieldInfo.FieldType; else if (MemberInfo is PropertyInfo prop) _memberType = prop.PropertyType; else _memberType = (Type)MemberInfo!; } return _memberType; } } internal DataContract MemberTypeContract { [RequiresDynamicCode(DataContract.SerializerAOTWarning)] [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get { if (_memberTypeContract == null) { if (IsGetOnlyCollection) { _memberTypeContract = DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(MemberType.TypeHandle), MemberType.TypeHandle, MemberType); } else { _memberTypeContract = DataContract.GetDataContract(MemberType); } } return _memberTypeContract; } set { _memberTypeContract = value; } } internal bool HasConflictingNameAndType { get => _hasConflictingNameAndType; set => _hasConflictingNameAndType = value; } internal DataMember? ConflictingMember { get => _conflictingMember; set => _conflictingMember = value; } private PrimitiveDataContract? _memberPrimitiveContract; internal PrimitiveDataContract? MemberPrimitiveContract { [RequiresDynamicCode(DataContract.SerializerAOTWarning)] [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get { if (_memberPrimitiveContract == PrimitiveDataContract.NullContract) { _memberPrimitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(MemberType); } return _memberPrimitiveContract; } } } /// <SecurityNote> /// Review - checks member visibility to calculate if access to it 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. /// </SecurityNote> internal bool RequiresMemberAccessForGet() { MemberInfo memberInfo = MemberInfo; FieldInfo? field = memberInfo as FieldInfo; if (field != null) { return DataContract.FieldRequiresMemberAccess(field); } else { PropertyInfo property = (PropertyInfo)memberInfo; MethodInfo? getMethod = property.GetMethod; if (getMethod != null) { return DataContract.MethodRequiresMemberAccess(getMethod) || !DataContract.IsTypeVisible(property.PropertyType); } } return false; } /// <SecurityNote> /// Review - checks member visibility to calculate if access to it 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. /// </SecurityNote> internal bool RequiresMemberAccessForSet() { MemberInfo memberInfo = MemberInfo; FieldInfo? field = memberInfo as FieldInfo; if (field != null) { return DataContract.FieldRequiresMemberAccess(field); } else { PropertyInfo property = (PropertyInfo)memberInfo; MethodInfo? setMethod = property.SetMethod; if (setMethod != null) { return DataContract.MethodRequiresMemberAccess(setMethod) || !DataContract.IsTypeVisible(property.PropertyType); } } return false; } [RequiresDynamicCode(DataContract.SerializerAOTWarning)] [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal DataMember BindGenericParameters(DataContract[] paramContracts, Dictionary<DataContract, DataContract>? boundContracts = null) { DataContract memberTypeContract = MemberTypeContract.BindGenericParameters(paramContracts, boundContracts); DataMember boundDataMember = new DataMember(memberTypeContract, Name, !memberTypeContract.IsValueType, IsRequired, EmitDefaultValue, Order); return boundDataMember; } [RequiresDynamicCode(DataContract.SerializerAOTWarning)] [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal bool Equals(object? other, HashSet<DataContractPairKey>? checkedContracts) { if (this == other) return true; if (other is DataMember dataMember) { // Note: comparison does not use Order hint since it influences element order but does not specify exact order bool thisIsNullable = (MemberTypeContract == null) ? false : !MemberTypeContract.IsValueType; bool dataMemberIsNullable = (dataMember.MemberTypeContract == null) ? false : !dataMember.MemberTypeContract.IsValueType; return (Name == dataMember.Name && (IsNullable || thisIsNullable) == (dataMember.IsNullable || dataMemberIsNullable) && IsRequired == dataMember.IsRequired && EmitDefaultValue == dataMember.EmitDefaultValue && MemberTypeContract!.Equals(dataMember.MemberTypeContract, checkedContracts)); } return false; } } }