< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Runtime.Serialization.ClassDataContractEx
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Runtime/Serialization/DataContractEx.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 57
Coverable lines: 57
Total lines: 662
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 52
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
Equals(...)0%40400%
IsEveryDataMemberOptional(...)0%440%
.cctor()100%110%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Runtime/Serialization/DataContractEx.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections;
 6using System.Collections.Generic;
 7using System.Linq.Expressions;
 8using System.Reflection;
 9using System.Runtime.Serialization;
 10using System.Xml;
 11using System.Xml.Schema;
 12
 13namespace CoreWCF.Runtime.Serialization
 14{
 15    internal class DataContractEx
 16    {
 17        protected DataContractEx(object dataContract)
 18        {
 19            WrappedDataContract = dataContract ?? throw new ArgumentNullException(nameof(dataContract));
 20            Fx.Assert(DataContractType.IsAssignableFrom(dataContract.GetType()), "Only types derived from DataContract c
 21        }
 22
 23        public object WrappedDataContract { get; }
 24
 25        public IDictionary KnownDataContracts => s_getKnownDataContracts(WrappedDataContract);
 26        public Type UnderlyingType => s_getUnderlyingType(WrappedDataContract);
 27        public XmlQualifiedName StableName => s_getStableName(WrappedDataContract);
 28        public XmlDictionaryString TopLevelElementName => s_getTopLevelElementName(WrappedDataContract);
 29        public XmlDictionaryString TopLevelElementNamespace => s_getTopLevelElementNamespace(WrappedDataContract);
 30        public bool HasRoot => s_getHasRoot(WrappedDataContract);
 31        public bool IsBuiltInDataContract => s_getIsBuiltInDataContract(WrappedDataContract);
 32        public bool IsReference => s_getIsReference(WrappedDataContract);
 33        public bool IsISerializable => s_getIsISerializable(WrappedDataContract);
 34        public bool IsValueType
 35        {
 36            get => s_getIsValueType(WrappedDataContract);
 37            set => s_setIsValueType(WrappedDataContract, value);
 38        }
 39
 40        public sealed override bool Equals(object other)
 41        {
 42            Fx.Assert(!(other is DataContractEx), "The unwrapped DataContract should be passed to equals");
 43            if (WrappedDataContract == other)
 44                return true;
 45
 46            return Equals(other, new Dictionary<DataContractPairKey, object>());
 47        }
 48
 49        public override int GetHashCode()
 50        {
 51            return base.GetHashCode();
 52        }
 53
 54        internal virtual bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
 55        {
 56            DataContractEx dataContract = Wrap(other);
 57            if (dataContract != null)
 58            {
 59                return StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.StableNam
 60            }
 61
 62            return false;
 63        }
 64
 65        internal bool IsEqualOrChecked(object other, Dictionary<DataContractPairKey, object> checkedContracts)
 66        {
 67            if (WrappedDataContract == other)
 68                return true;
 69
 70            if (checkedContracts != null)
 71            {
 72                DataContractPairKey contractPairKey = new DataContractPairKey(WrappedDataContract, other);
 73                if (checkedContracts.ContainsKey(contractPairKey))
 74                    return true;
 75                checkedContracts.Add(contractPairKey, null);
 76            }
 77
 78            return false;
 79        }
 80
 81        internal static string GetClrTypeFullName(Type type)
 82        {
 83            return !type.IsGenericTypeDefinition && type.ContainsGenericParameters ? type.Namespace + "." + type.Name : 
 84        }
 85
 86        internal static Func<Type, DataContractEx> GetDataContract { private set; get; } = GetDataContractStub;
 87        internal static Func<int, RuntimeTypeHandle, Type, int, DataContractEx> GetGetOnlyCollectionDataContract { priva
 88        internal static Func<RuntimeTypeHandle, int> GetId { private set; get; } = GetIdStub;
 89        internal static Type DataContractType => typeof(DataContractSerializer).Assembly.GetType("System.Runtime.Seriali
 90        protected static readonly Type ClassDataContractType = typeof(DataContractSerializer).Assembly.GetType("System.R
 91        protected static readonly Type CollectionDataContractType = typeof(DataContractSerializer).Assembly.GetType("Sys
 92        protected static readonly Type EnumDataContractType = typeof(DataContractSerializer).Assembly.GetType("System.Ru
 93        protected static readonly Type PrimitiveDataContractType = typeof(DataContractSerializer).Assembly.GetType("Syst
 94        protected static readonly Type XmlDataContractType = typeof(DataContractSerializer).Assembly.GetType("System.Run
 95        protected static readonly Type SchemaExportertType = typeof(DataContractSerializer).Assembly.GetType("System.Run
 96        private static readonly Type SerializationModeType = typeof(DataContractSerializer).Assembly.GetType("System.Run
 97
 98        private static readonly Func<object, Type> s_getUnderlyingType = ReflectionHelper.GetPropertyDelegate<Type>(Data
 99        private static readonly Func<object, XmlQualifiedName> s_getStableName = ReflectionHelper.GetPropertyDelegate<Xm
 100        private static readonly Func<object, XmlDictionaryString> s_getTopLevelElementName = ReflectionHelper.GetPropert
 101        private static readonly Func<object, XmlDictionaryString> s_getTopLevelElementNamespace = ReflectionHelper.GetPr
 102        private static readonly Func<object, bool> s_getHasRoot = ReflectionHelper.GetPropertyDelegate<bool>(DataContrac
 103        private static readonly Func<object, bool> s_getIsBuiltInDataContract = ReflectionHelper.GetPropertyDelegate<boo
 104        private static readonly Func<object, bool> s_getIsReference = ReflectionHelper.GetPropertyDelegate<bool>(DataCon
 105        private static readonly Func<object, bool> s_getIsISerializable = ReflectionHelper.GetPropertyDelegate<bool>(Dat
 106        private static readonly Func<object, bool> s_getIsValueType = ReflectionHelper.GetPropertyDelegate<bool>(DataCon
 107        private static readonly Action<object, bool> s_setIsValueType = ReflectionHelper.SetPropertyDelegate<bool>(DataC
 108        private static readonly Func<object, IDictionary> s_getKnownDataContracts = ReflectionHelper.GetPropertyDelegate
 109
 110        private static DataContractEx GetDataContractStub(Type clrType)
 111        {
 112            var methodInfo = DataContractType.GetMethod("GetDataContract", BindingFlags.Static | BindingFlags.NonPublic,
 113            var getDataContractDelegate = ReflectionHelper.CreateStaticMethodCallLambda<Type, object>(methodInfo);
 114            Func<Type, DataContractEx> wrappingDelegate = (Type type) => Wrap(getDataContractDelegate(type));
 115            GetDataContract = wrappingDelegate;
 116            return GetDataContract(clrType);
 117        }
 118
 119        private static DataContractEx GetGetOnlyCollectionDataContractStub(int id, RuntimeTypeHandle typeHandle, Type ty
 120        {
 121            var methodInfo = DataContractType.GetMethod("GetGetOnlyCollectionDataContract", BindingFlags.Static | Bindin
 122                new Type[] { typeof(int), typeof(RuntimeTypeHandle), typeof(Type), SerializationModeType }, null);
 123            var idParam = Expression.Parameter(typeof(int), "id");
 124            var typeHandleParam = Expression.Parameter(typeof(RuntimeTypeHandle), "typeHandle");
 125            var typeParam = Expression.Parameter(typeof(Type), "type");
 126            var intModeParam = Expression.Parameter(typeof(int), "mode");
 127            var serializationModeParam = Expression.Convert(Expression.Constant(mode), SerializationModeType);
 128
 129            // Passing null as instance expression as static method call
 130            Expression callExpr = Expression.Call(methodInfo, idParam, typeHandleParam, typeParam, serializationModePara
 131            var lambdaExpr = Expression.Lambda<Func<int, RuntimeTypeHandle, Type, int, object>>(callExpr, idParam, typeH
 132            var getGetOnlyCollectionDataContractDelegate = lambdaExpr.Compile();
 133            Func<int, RuntimeTypeHandle, Type, int, DataContractEx> wrappingDelegate =
 134                (int idp, RuntimeTypeHandle typeHandlep, Type typep, int modep) =>
 135                {
 136                    return Wrap(getGetOnlyCollectionDataContractDelegate(idp, typeHandlep, typep, modep));
 137                };
 138            GetGetOnlyCollectionDataContract = wrappingDelegate;
 139            return GetGetOnlyCollectionDataContract(id, typeHandle, type, mode);
 140        }
 141
 142        private static int GetIdStub(RuntimeTypeHandle typeHandle)
 143        {
 144            var methodInfo = DataContractType.GetMethod("GetId", BindingFlags.Static | BindingFlags.NonPublic, null, new
 145            var getIdDelegate = ReflectionHelper.CreateStaticMethodCallLambda<RuntimeTypeHandle, int>(methodInfo);
 146            GetId = getIdDelegate;
 147            return GetId(typeHandle);
 148        }
 149
 150        internal static DataContractEx Wrap(object dataContract)
 151        {
 152            Fx.Assert(!(dataContract is DataContractEx), "Attempting to wrap a DataContractEx");
 153
 154            var dataContractType = dataContract.GetType();
 155            if (ClassDataContractType.Equals(dataContractType))
 156            {
 157                return new ClassDataContractEx(dataContract);
 158            }
 159            else if (CollectionDataContractType.Equals(dataContractType))
 160            {
 161                return new CollectionDataContractEx(dataContract);
 162            }
 163            else if (EnumDataContractType.Equals(dataContractType))
 164            {
 165                return new EnumDataContractEx(dataContract);
 166            }
 167            else if (PrimitiveDataContractType.IsAssignableFrom(dataContractType))
 168            {
 169                return new PrimitiveDataContractEx(dataContract);
 170            }
 171            else if (XmlDataContractType.Equals(dataContractType))
 172            {
 173                return new XmlDataContractEx(dataContract);
 174            }
 175            else
 176            {
 177                Fx.Assert($"Unrecognized data contract type {dataContractType}");
 178                return null;
 179            }
 180        }
 181    }
 182
 183    internal class ClassDataContractEx : DataContractEx
 184    {
 185        private List<DataMemberEx> _wrappedMembersList;
 186        private ClassDataContractEx _baseContract;
 187
 0188        public ClassDataContractEx(object dataContract) : base(dataContract)
 189        {
 190            Fx.Assert(ClassDataContractType.Equals(dataContract.GetType()), "Only ClassDataContract can be wrapped");
 0191        }
 192
 193        public ClassDataContractEx BaseContract
 194        {
 195            get
 196            {
 0197                if (_baseContract == null)
 198                {
 0199                    var baseContract = s_getBaseContract(WrappedDataContract);
 0200                    if (baseContract != null)
 201                    {
 0202                        _baseContract = new ClassDataContractEx(baseContract);
 203                    }
 204                }
 205
 0206                return _baseContract;
 207            }
 208        }
 209
 210        public List<DataMemberEx> Members
 211        {
 212            get
 213            {
 0214                if (_wrappedMembersList == null)
 215                {
 0216                    var dataMembersList = s_getMembers(WrappedDataContract);
 0217                    _wrappedMembersList = new List<DataMemberEx>(dataMembersList.Count);
 0218                    foreach(var member in dataMembersList)
 219                    {
 0220                        _wrappedMembersList.Add(new DataMemberEx(member));
 221                    }
 222                }
 223
 0224                return _wrappedMembersList;
 225            }
 226        }
 227
 228        internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
 229        {
 0230            if (IsEqualOrChecked(other, checkedContracts))
 0231                return true;
 232
 0233            if (base.Equals(other, checkedContracts))
 234            {
 0235                if (ClassDataContractType.Equals(other?.GetType()))
 236                {
 0237                    ClassDataContractEx dataContract = new ClassDataContractEx(other);
 0238                    if (IsISerializable)
 239                    {
 0240                        if (!dataContract.IsISerializable)
 0241                            return false;
 242                    }
 243                    else
 244                    {
 0245                        if (dataContract.IsISerializable)
 0246                            return false;
 247
 0248                        if (Members == null)
 249                        {
 0250                            if (dataContract.Members != null)
 251                            {
 252                                // check that all the datamembers in dataContract.Members are optional
 0253                                if (!IsEveryDataMemberOptional(dataContract.Members))
 0254                                    return false;
 255                            }
 256                        }
 0257                        else if (dataContract.Members == null)
 258                        {
 259                            // check that all the datamembers in Members are optional
 0260                            if (!IsEveryDataMemberOptional(Members))
 0261                                return false;
 262                        }
 263                        else
 264                        {
 0265                            Dictionary<string, DataMemberEx> membersDictionary = new Dictionary<string, DataMemberEx>(Me
 0266                            List<DataMemberEx> dataContractMembersList = new List<DataMemberEx>();
 0267                            for (int i = 0; i < Members.Count; i++)
 268                            {
 0269                                membersDictionary.Add(Members[i].Name, Members[i]);
 270                            }
 271
 0272                            for (int i = 0; i < dataContract.Members.Count; i++)
 273                            {
 274                                // check that all datamembers common to both datacontracts match
 275                                DataMemberEx dataMember;
 0276                                if (membersDictionary.TryGetValue(dataContract.Members[i].Name, out dataMember))
 277                                {
 0278                                    if (dataMember.Equals(dataContract.Members[i], checkedContracts))
 279                                    {
 0280                                        membersDictionary.Remove(dataMember.Name);
 281                                    }
 282                                    else
 283                                    {
 0284                                        return false;
 285                                    }
 286                                }
 287                                // otherwise save the non-matching datamembers for later verification
 288                                else
 289                                {
 0290                                    dataContractMembersList.Add(dataContract.Members[i]);
 291                                }
 292                            }
 293
 294                            // check that datamembers left over from either datacontract are optional
 0295                            if (!IsEveryDataMemberOptional(membersDictionary.Values))
 0296                                return false;
 0297                            if (!IsEveryDataMemberOptional(dataContractMembersList))
 0298                                return false;
 299
 300                        }
 301                    }
 302
 0303                    if (BaseContract == null)
 0304                        return (dataContract.BaseContract == null);
 0305                    else if (dataContract.BaseContract == null)
 0306                        return false;
 307                    else
 0308                        return BaseContract.Equals(dataContract.BaseContract.WrappedDataContract, checkedContracts);
 309                }
 310            }
 311
 0312            return false;
 313        }
 314
 315        private bool IsEveryDataMemberOptional(IEnumerable<DataMemberEx> dataMembers)
 316        {
 0317            foreach (var dataMember in dataMembers)
 318            {
 0319                if (dataMember.IsRequired)
 0320                    return false;
 321            }
 0322            return true;
 0323        }
 324
 0325        private static readonly Func<object, IList> s_getMembers = ReflectionHelper.GetPropertyDelegate<IList>(ClassData
 0326        private static readonly Func<object, object> s_getBaseContract = ReflectionHelper.GetPropertyDelegate<object>(Cl
 327    }
 328
 329    internal class CollectionDataContractEx : DataContractEx
 330    {
 331        private DataContractEx _itemContract;
 332
 333        public CollectionDataContractEx(object dataContract) : base(dataContract)
 334        {
 335            Fx.Assert(CollectionDataContractType.Equals(dataContract.GetType()), "Only CollectionDataContract can be wra
 336            if(ItemContract?.UnderlyingType != null && ItemContract.UnderlyingType.Name.StartsWith("KeyValuePairAdapter"
 337            {
 338                ItemContract.IsValueType = true;
 339                if (ItemContract is ClassDataContractEx classDataContract)
 340                {
 341                    foreach (var member in classDataContract.Members)
 342                    {
 343                        member.IsRequired = true;
 344                    }
 345                }
 346            }
 347        }
 348
 349        public DataContractEx ItemContract
 350        {
 351            get
 352            {
 353                if (_itemContract == null)
 354                {
 355                    var itemContract = s_getItemContract(WrappedDataContract);
 356                    if (itemContract != null)
 357                    {
 358                        _itemContract = Wrap(itemContract);
 359                    }
 360                }
 361
 362                return _itemContract;
 363            }
 364        }
 365
 366        public string ItemName => s_getItemName(WrappedDataContract);
 367        public Type ItemType => s_getItemType(WrappedDataContract);
 368        public bool IsDictionary => s_getIsDictionary(WrappedDataContract);
 369        public bool IsItemTypeNullable => s_getIsItemTypeNullable(WrappedDataContract);
 370
 371        internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
 372        {
 373            if (IsEqualOrChecked(other, checkedContracts))
 374                return true;
 375
 376            if (base.Equals(other, checkedContracts))
 377            {
 378                if (CollectionDataContractType.Equals(other?.GetType()))
 379                {
 380                    CollectionDataContractEx dataContract = new CollectionDataContractEx(other);
 381                    bool thisItemTypeIsNullable = (ItemContract == null) ? false : !ItemContract.IsValueType;
 382                    bool otherItemTypeIsNullable = (dataContract.ItemContract == null) ? false : !dataContract.ItemContr
 383                    return ItemName == dataContract.ItemName &&
 384                        (IsItemTypeNullable || thisItemTypeIsNullable) == (dataContract.IsItemTypeNullable || otherItemT
 385                        ItemContract.Equals(dataContract.ItemContract.WrappedDataContract, checkedContracts);
 386                }
 387            }
 388            return false;
 389        }
 390
 391        private static readonly Func<object, object> s_getItemContract = ReflectionHelper.GetPropertyDelegate<object>(Co
 392        private static readonly Func<object, string> s_getItemName = ReflectionHelper.GetPropertyDelegate<string>(Collec
 393        private static readonly Func<object, Type> s_getItemType = ReflectionHelper.GetPropertyDelegate<Type>(Collection
 394        private static readonly Func<object, bool> s_getIsDictionary = ReflectionHelper.GetPropertyDelegate<bool>(Collec
 395        private static readonly Func<object, bool> s_getIsItemTypeNullable = ReflectionHelper.GetPropertyDelegate<bool>(
 396    }
 397
 398    internal class EnumDataContractEx : DataContractEx
 399    {
 400        private List<DataMemberEx> _wrappedMembersList;
 401
 402        public EnumDataContractEx(object dataContract) : base(dataContract)
 403        {
 404            Fx.Assert(EnumDataContractType.Equals(dataContract.GetType()), "Only EnumDataContract can be wrapped");
 405            var dataType = UnderlyingType; // Type that DataContract is for
 406            Fx.Assert(dataType.IsEnum, "EnumDataContract should only be created for an enum type");
 407            var underlyingType = Enum.GetUnderlyingType(dataType); // The underlying integer type backing the Enum
 408            Fx.Assert(s_typeToName.ContainsKey(underlyingType), $"Enum underlying type {underlyingType} is missing from 
 409            BaseContractName = s_typeToName[underlyingType];
 410        }
 411
 412        public XmlQualifiedName BaseContractName
 413        {
 414            set => s_setBaseContractName(WrappedDataContract, value);
 415        }
 416
 417        public List<DataMemberEx> Members
 418        {
 419            get
 420            {
 421                if (_wrappedMembersList == null)
 422                {
 423                    var dataMembersList = s_getMembers(WrappedDataContract);
 424                    _wrappedMembersList = new List<DataMemberEx>(dataMembersList.Count);
 425                    foreach (var member in dataMembersList)
 426                    {
 427                        _wrappedMembersList.Add(new DataMemberEx(member));
 428                    }
 429                }
 430
 431                return _wrappedMembersList;
 432            }
 433        }
 434
 435        public List<long> Values => s_getValues(WrappedDataContract);
 436        public bool IsFlags => s_getIsFlags(WrappedDataContract);
 437
 438        internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
 439        {
 440            if (IsEqualOrChecked(other, checkedContracts))
 441                return true;
 442
 443            if (base.Equals(other, null))
 444            {
 445                if (EnumDataContractType.Equals(other?.GetType()))
 446                {
 447                    EnumDataContractEx dataContract = new EnumDataContractEx(other);
 448                    if (Members.Count != dataContract.Members.Count || Values.Count != dataContract.Values.Count)
 449                        return false;
 450                    string[] memberNames1 = new string[Members.Count], memberNames2 = new string[Members.Count];
 451                    for (int i = 0; i < Members.Count; i++)
 452                    {
 453                        memberNames1[i] = Members[i].Name;
 454                        memberNames2[i] = dataContract.Members[i].Name;
 455                    }
 456                    Array.Sort(memberNames1);
 457                    Array.Sort(memberNames2);
 458                    for (int i = 0; i < Members.Count; i++)
 459                    {
 460                        if (memberNames1[i] != memberNames2[i])
 461                            return false;
 462                    }
 463
 464                    return IsFlags == dataContract.IsFlags;
 465                }
 466            }
 467            return false;
 468        }
 469
 470        private static readonly Func<object, IList> s_getMembers = ReflectionHelper.GetPropertyDelegate<IList>(EnumDataC
 471        private static readonly Func<object, List<long>> s_getValues = ReflectionHelper.GetPropertyDelegate<List<long>>(
 472        private static readonly Func<object, bool> s_getIsFlags = ReflectionHelper.GetPropertyDelegate <bool>(EnumDataCo
 473        private static readonly Action<object, XmlQualifiedName> s_setBaseContractName = ReflectionHelper.SetPropertyDel
 474
 475        private static readonly Dictionary<Type, XmlQualifiedName> s_typeToName = new Dictionary<Type, XmlQualifiedName>
 476        {
 477            [typeof(sbyte)] = new XmlQualifiedName("byte", XmlSchema.Namespace),
 478            [typeof(byte)] = new XmlQualifiedName("unsignedByte", XmlSchema.Namespace),
 479            [typeof(short)] = new XmlQualifiedName("short", XmlSchema.Namespace),
 480            [typeof(ushort)] = new XmlQualifiedName("unsignedShort", XmlSchema.Namespace),
 481            [typeof(int)] = new XmlQualifiedName("int", XmlSchema.Namespace),
 482            [typeof(uint)] = new XmlQualifiedName("unsignedInt", XmlSchema.Namespace),
 483            [typeof(long)] = new XmlQualifiedName("long", XmlSchema.Namespace),
 484            [typeof(ulong)] = new XmlQualifiedName("unsignedLong", XmlSchema.Namespace)
 485        };
 486    }
 487
 488    internal class PrimitiveDataContractEx : DataContractEx
 489    {
 490        public PrimitiveDataContractEx(object dataContract) : base(dataContract)
 491        {
 492            Fx.Assert(PrimitiveDataContractType.IsAssignableFrom(dataContract.GetType()), "Only PrimitiveDataContract or
 493        }
 494
 495        internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
 496        {
 497            if (PrimitiveDataContractType.IsAssignableFrom(other?.GetType()))
 498            {
 499                Type thisType = WrappedDataContract.GetType();
 500                Type otherType = other.GetType();
 501                return (thisType.Equals(otherType) || thisType.IsSubclassOf(otherType) || otherType.IsSubclassOf(thisTyp
 502            }
 503            return false;
 504        }
 505    }
 506
 507    internal class XmlDataContractEx : DataContractEx
 508    {
 509        public XmlDataContractEx(object dataContract) : base(dataContract)
 510        {
 511            Fx.Assert(XmlDataContractType.Equals(dataContract.GetType()), "Only XmlDataContract can be wrapped");
 512            if (XsdType == null)
 513            {
 514                XsdType = GetXmlTypeInfo(UnderlyingType);
 515            }
 516        }
 517
 518        public bool IsAnonymous => s_getIsAnonymous(WrappedDataContract);
 519        public XmlSchemaType XsdType
 520        {
 521            get => s_getXsdType(WrappedDataContract);
 522            set => s_setXsdType(WrappedDataContract, value);
 523        }
 524
 525        internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
 526        {
 527            if (IsEqualOrChecked(other, checkedContracts))
 528                return true;
 529
 530            if (XmlDataContractType.Equals(other?.GetType()))
 531            {
 532                XmlDataContractEx dataContract = new XmlDataContractEx(other);
 533                if (HasRoot != dataContract.HasRoot)
 534                    return false;
 535
 536                if (IsAnonymous)
 537                {
 538                    return dataContract.IsAnonymous;
 539                }
 540                else
 541                {
 542                    return StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.Stabl
 543                }
 544            }
 545            return false;
 546        }
 547
 548        private static XmlSchemaType GetXmlTypeInfo(Type type)
 549        {
 550            var getXmlTypeInfoMethod = SchemaExportertType.GetMethod("GetXmlTypeInfo", BindingFlags.Static | BindingFlag
 551            var getXmlTypeInfo = getXmlTypeInfoMethod.CreateDelegate(typeof(GetXmlTypeInfoDelegate), null) as GetXmlType
 552            XmlSchemaType xsdType;
 553            getXmlTypeInfo(type, out _, out xsdType, out _);
 554            return xsdType;
 555        }
 556
 557        private delegate void GetXmlTypeInfoDelegate(Type type, out XmlQualifiedName stableName, out XmlSchemaType xsdTy
 558        private static readonly Func<object, bool> s_getIsAnonymous = ReflectionHelper.GetPropertyDelegate<bool>(XmlData
 559        private static readonly Func<object, XmlSchemaType> s_getXsdType = ReflectionHelper.GetPropertyDelegate<XmlSchem
 560        private static readonly Action<object, XmlSchemaType> s_setXsdType = ReflectionHelper.SetPropertyDelegate<XmlSch
 561    }
 562
 563    internal class DataMemberEx
 564    {
 565        private DataContractEx _memberTypeContract;
 566
 567        public DataMemberEx(object dataMember)
 568        {
 569            WrappedDataMember = dataMember ?? throw new ArgumentNullException(nameof(dataMember));
 570            Fx.Assert(s_dataMemberType.Equals(dataMember.GetType()), "Only DataMember can be wrapped");
 571        }
 572
 573        private object WrappedDataMember { get; }
 574
 575        public MemberInfo MemberInfo => s_getMemberInfo(WrappedDataMember);
 576        public Type MemberType => s_getMemberType(WrappedDataMember);
 577        public bool EmitDefaultValue => s_getEmitDefaultValue(WrappedDataMember);
 578        public bool IsGetOnlyCollection => s_getIsGetOnlyCollection(WrappedDataMember);
 579        public bool IsNullable => s_getIsNullable(WrappedDataMember);
 580        public bool IsRequired
 581        {
 582            get => s_getIsRequired(WrappedDataMember);
 583            set => s_setIsRequired(WrappedDataMember, value);
 584        }
 585
 586        public string Name => s_getName(WrappedDataMember);
 587
 588        public DataContractEx MemberTypeContract
 589        {
 590            get
 591            {
 592                if (_memberTypeContract == null)
 593                {
 594                    var memberTypeContract = s_getMemberTypeContract(WrappedDataMember);
 595                    if (memberTypeContract != null)
 596                    {
 597                        _memberTypeContract = DataContractEx.Wrap(memberTypeContract);
 598                    }
 599                }
 600
 601                return _memberTypeContract;
 602            }
 603        }
 604
 605        internal bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts)
 606        {
 607            if (this == other)
 608                return true;
 609
 610            DataMemberEx dataMember = other as DataMemberEx;
 611            if (dataMember != null)
 612            {
 613                // Note: comparison does not use Order hint since it influences element order but does not specify exact
 614                bool thisIsNullable = (MemberTypeContract == null) ? false : !MemberTypeContract.IsValueType;
 615                bool dataMemberIsNullable = (dataMember.MemberTypeContract == null) ? false : !dataMember.MemberTypeCont
 616                return Name == dataMember.Name
 617                       && (IsNullable || thisIsNullable) == (dataMember.IsNullable || dataMemberIsNullable)
 618                       && IsRequired == dataMember.IsRequired
 619                       && EmitDefaultValue == dataMember.EmitDefaultValue
 620                       && MemberTypeContract.Equals(dataMember.MemberTypeContract.WrappedDataContract, checkedContracts)
 621            }
 622            return false;
 623        }
 624
 625        private static readonly Type s_dataMemberType = typeof(DataContractSerializer).Assembly.GetType("System.Runtime.
 626
 627        private static readonly Func<object, MemberInfo> s_getMemberInfo = ReflectionHelper.GetPropertyDelegate<MemberIn
 628        private static readonly Func<object, Type> s_getMemberType = ReflectionHelper.GetPropertyDelegate<Type>(s_dataMe
 629        private static readonly Func<object, bool> s_getEmitDefaultValue = ReflectionHelper.GetPropertyDelegate<bool>(s_
 630        private static readonly Func<object, bool> s_getIsGetOnlyCollection = ReflectionHelper.GetPropertyDelegate<bool>
 631        private static readonly Func<object, bool> s_getIsRequired = ReflectionHelper.GetPropertyDelegate<bool>(s_dataMe
 632        private static readonly Action<object, bool> s_setIsRequired = ReflectionHelper.SetPropertyDelegate<bool>(s_data
 633        private static readonly Func<object, bool> s_getIsNullable = ReflectionHelper.GetPropertyDelegate<bool>(s_dataMe
 634        private static readonly Func<object, string> s_getName = ReflectionHelper.GetPropertyDelegate<string>(s_dataMemb
 635        private static readonly Func<object, object> s_getMemberTypeContract = ReflectionHelper.GetPropertyDelegate<obje
 636    }
 637
 638    internal class DataContractPairKey
 639    {
 640        private readonly object _object1;
 641        private readonly object _object2;
 642
 643        public DataContractPairKey(object object1, object object2)
 644        {
 645            _object1 = object1;
 646            _object2 = object2;
 647        }
 648
 649        public override bool Equals(object other)
 650        {
 651            DataContractPairKey otherKey = other as DataContractPairKey;
 652            if (otherKey == null)
 653                return false;
 654            return (otherKey._object1 == _object1 && otherKey._object2 == _object2) || (otherKey._object1 == _object2 &&
 655        }
 656
 657        public override int GetHashCode()
 658        {
 659            return _object1.GetHashCode() ^ _object2.GetHashCode();
 660        }
 661    }
 662}