| | | 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 | | |
| | | 4 | | using System; |
| | | 5 | | using System.Collections; |
| | | 6 | | using System.Collections.Generic; |
| | | 7 | | using System.Linq.Expressions; |
| | | 8 | | using System.Reflection; |
| | | 9 | | using System.Runtime.Serialization; |
| | | 10 | | using System.Xml; |
| | | 11 | | using System.Xml.Schema; |
| | | 12 | | |
| | | 13 | | namespace 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 | | |
| | | 188 | | public ClassDataContractEx(object dataContract) : base(dataContract) |
| | | 189 | | { |
| | | 190 | | Fx.Assert(ClassDataContractType.Equals(dataContract.GetType()), "Only ClassDataContract can be wrapped"); |
| | | 191 | | } |
| | | 192 | | |
| | | 193 | | public ClassDataContractEx BaseContract |
| | | 194 | | { |
| | | 195 | | get |
| | | 196 | | { |
| | | 197 | | if (_baseContract == null) |
| | | 198 | | { |
| | | 199 | | var baseContract = s_getBaseContract(WrappedDataContract); |
| | | 200 | | if (baseContract != null) |
| | | 201 | | { |
| | | 202 | | _baseContract = new ClassDataContractEx(baseContract); |
| | | 203 | | } |
| | | 204 | | } |
| | | 205 | | |
| | | 206 | | return _baseContract; |
| | | 207 | | } |
| | | 208 | | } |
| | | 209 | | |
| | | 210 | | public List<DataMemberEx> Members |
| | | 211 | | { |
| | | 212 | | get |
| | | 213 | | { |
| | | 214 | | if (_wrappedMembersList == null) |
| | | 215 | | { |
| | | 216 | | var dataMembersList = s_getMembers(WrappedDataContract); |
| | | 217 | | _wrappedMembersList = new List<DataMemberEx>(dataMembersList.Count); |
| | | 218 | | foreach(var member in dataMembersList) |
| | | 219 | | { |
| | | 220 | | _wrappedMembersList.Add(new DataMemberEx(member)); |
| | | 221 | | } |
| | | 222 | | } |
| | | 223 | | |
| | | 224 | | return _wrappedMembersList; |
| | | 225 | | } |
| | | 226 | | } |
| | | 227 | | |
| | | 228 | | internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts) |
| | | 229 | | { |
| | | 230 | | if (IsEqualOrChecked(other, checkedContracts)) |
| | | 231 | | return true; |
| | | 232 | | |
| | | 233 | | if (base.Equals(other, checkedContracts)) |
| | | 234 | | { |
| | | 235 | | if (ClassDataContractType.Equals(other?.GetType())) |
| | | 236 | | { |
| | | 237 | | ClassDataContractEx dataContract = new ClassDataContractEx(other); |
| | | 238 | | if (IsISerializable) |
| | | 239 | | { |
| | | 240 | | if (!dataContract.IsISerializable) |
| | | 241 | | return false; |
| | | 242 | | } |
| | | 243 | | else |
| | | 244 | | { |
| | | 245 | | if (dataContract.IsISerializable) |
| | | 246 | | return false; |
| | | 247 | | |
| | | 248 | | if (Members == null) |
| | | 249 | | { |
| | | 250 | | if (dataContract.Members != null) |
| | | 251 | | { |
| | | 252 | | // check that all the datamembers in dataContract.Members are optional |
| | | 253 | | if (!IsEveryDataMemberOptional(dataContract.Members)) |
| | | 254 | | return false; |
| | | 255 | | } |
| | | 256 | | } |
| | | 257 | | else if (dataContract.Members == null) |
| | | 258 | | { |
| | | 259 | | // check that all the datamembers in Members are optional |
| | | 260 | | if (!IsEveryDataMemberOptional(Members)) |
| | | 261 | | return false; |
| | | 262 | | } |
| | | 263 | | else |
| | | 264 | | { |
| | | 265 | | Dictionary<string, DataMemberEx> membersDictionary = new Dictionary<string, DataMemberEx>(Me |
| | | 266 | | List<DataMemberEx> dataContractMembersList = new List<DataMemberEx>(); |
| | | 267 | | for (int i = 0; i < Members.Count; i++) |
| | | 268 | | { |
| | | 269 | | membersDictionary.Add(Members[i].Name, Members[i]); |
| | | 270 | | } |
| | | 271 | | |
| | | 272 | | for (int i = 0; i < dataContract.Members.Count; i++) |
| | | 273 | | { |
| | | 274 | | // check that all datamembers common to both datacontracts match |
| | | 275 | | DataMemberEx dataMember; |
| | | 276 | | if (membersDictionary.TryGetValue(dataContract.Members[i].Name, out dataMember)) |
| | | 277 | | { |
| | | 278 | | if (dataMember.Equals(dataContract.Members[i], checkedContracts)) |
| | | 279 | | { |
| | | 280 | | membersDictionary.Remove(dataMember.Name); |
| | | 281 | | } |
| | | 282 | | else |
| | | 283 | | { |
| | | 284 | | return false; |
| | | 285 | | } |
| | | 286 | | } |
| | | 287 | | // otherwise save the non-matching datamembers for later verification |
| | | 288 | | else |
| | | 289 | | { |
| | | 290 | | dataContractMembersList.Add(dataContract.Members[i]); |
| | | 291 | | } |
| | | 292 | | } |
| | | 293 | | |
| | | 294 | | // check that datamembers left over from either datacontract are optional |
| | | 295 | | if (!IsEveryDataMemberOptional(membersDictionary.Values)) |
| | | 296 | | return false; |
| | | 297 | | if (!IsEveryDataMemberOptional(dataContractMembersList)) |
| | | 298 | | return false; |
| | | 299 | | |
| | | 300 | | } |
| | | 301 | | } |
| | | 302 | | |
| | | 303 | | if (BaseContract == null) |
| | | 304 | | return (dataContract.BaseContract == null); |
| | | 305 | | else if (dataContract.BaseContract == null) |
| | | 306 | | return false; |
| | | 307 | | else |
| | | 308 | | return BaseContract.Equals(dataContract.BaseContract.WrappedDataContract, checkedContracts); |
| | | 309 | | } |
| | | 310 | | } |
| | | 311 | | |
| | | 312 | | return false; |
| | | 313 | | } |
| | | 314 | | |
| | | 315 | | private bool IsEveryDataMemberOptional(IEnumerable<DataMemberEx> dataMembers) |
| | | 316 | | { |
| | | 317 | | foreach (var dataMember in dataMembers) |
| | | 318 | | { |
| | | 319 | | if (dataMember.IsRequired) |
| | | 320 | | return false; |
| | | 321 | | } |
| | | 322 | | return true; |
| | | 323 | | } |
| | | 324 | | |
| | | 325 | | private static readonly Func<object, IList> s_getMembers = ReflectionHelper.GetPropertyDelegate<IList>(ClassData |
| | | 326 | | 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 | | |
| | 0 | 402 | | public EnumDataContractEx(object dataContract) : base(dataContract) |
| | | 403 | | { |
| | | 404 | | Fx.Assert(EnumDataContractType.Equals(dataContract.GetType()), "Only EnumDataContract can be wrapped"); |
| | 0 | 405 | | var dataType = UnderlyingType; // Type that DataContract is for |
| | | 406 | | Fx.Assert(dataType.IsEnum, "EnumDataContract should only be created for an enum type"); |
| | 0 | 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 |
| | 0 | 409 | | BaseContractName = s_typeToName[underlyingType]; |
| | 0 | 410 | | } |
| | | 411 | | |
| | | 412 | | public XmlQualifiedName BaseContractName |
| | | 413 | | { |
| | 0 | 414 | | set => s_setBaseContractName(WrappedDataContract, value); |
| | | 415 | | } |
| | | 416 | | |
| | | 417 | | public List<DataMemberEx> Members |
| | | 418 | | { |
| | | 419 | | get |
| | | 420 | | { |
| | 0 | 421 | | if (_wrappedMembersList == null) |
| | | 422 | | { |
| | 0 | 423 | | var dataMembersList = s_getMembers(WrappedDataContract); |
| | 0 | 424 | | _wrappedMembersList = new List<DataMemberEx>(dataMembersList.Count); |
| | 0 | 425 | | foreach (var member in dataMembersList) |
| | | 426 | | { |
| | 0 | 427 | | _wrappedMembersList.Add(new DataMemberEx(member)); |
| | | 428 | | } |
| | | 429 | | } |
| | | 430 | | |
| | 0 | 431 | | return _wrappedMembersList; |
| | | 432 | | } |
| | | 433 | | } |
| | | 434 | | |
| | 0 | 435 | | public List<long> Values => s_getValues(WrappedDataContract); |
| | 0 | 436 | | public bool IsFlags => s_getIsFlags(WrappedDataContract); |
| | | 437 | | |
| | | 438 | | internal override bool Equals(object other, Dictionary<DataContractPairKey, object> checkedContracts) |
| | | 439 | | { |
| | 0 | 440 | | if (IsEqualOrChecked(other, checkedContracts)) |
| | 0 | 441 | | return true; |
| | | 442 | | |
| | 0 | 443 | | if (base.Equals(other, null)) |
| | | 444 | | { |
| | 0 | 445 | | if (EnumDataContractType.Equals(other?.GetType())) |
| | | 446 | | { |
| | 0 | 447 | | EnumDataContractEx dataContract = new EnumDataContractEx(other); |
| | 0 | 448 | | if (Members.Count != dataContract.Members.Count || Values.Count != dataContract.Values.Count) |
| | 0 | 449 | | return false; |
| | 0 | 450 | | string[] memberNames1 = new string[Members.Count], memberNames2 = new string[Members.Count]; |
| | 0 | 451 | | for (int i = 0; i < Members.Count; i++) |
| | | 452 | | { |
| | 0 | 453 | | memberNames1[i] = Members[i].Name; |
| | 0 | 454 | | memberNames2[i] = dataContract.Members[i].Name; |
| | | 455 | | } |
| | 0 | 456 | | Array.Sort(memberNames1); |
| | 0 | 457 | | Array.Sort(memberNames2); |
| | 0 | 458 | | for (int i = 0; i < Members.Count; i++) |
| | | 459 | | { |
| | 0 | 460 | | if (memberNames1[i] != memberNames2[i]) |
| | 0 | 461 | | return false; |
| | | 462 | | } |
| | | 463 | | |
| | 0 | 464 | | return IsFlags == dataContract.IsFlags; |
| | | 465 | | } |
| | | 466 | | } |
| | 0 | 467 | | return false; |
| | | 468 | | } |
| | | 469 | | |
| | 0 | 470 | | private static readonly Func<object, IList> s_getMembers = ReflectionHelper.GetPropertyDelegate<IList>(EnumDataC |
| | 0 | 471 | | private static readonly Func<object, List<long>> s_getValues = ReflectionHelper.GetPropertyDelegate<List<long>>( |
| | 0 | 472 | | private static readonly Func<object, bool> s_getIsFlags = ReflectionHelper.GetPropertyDelegate <bool>(EnumDataCo |
| | 0 | 473 | | private static readonly Action<object, XmlQualifiedName> s_setBaseContractName = ReflectionHelper.SetPropertyDel |
| | | 474 | | |
| | 0 | 475 | | private static readonly Dictionary<Type, XmlQualifiedName> s_typeToName = new Dictionary<Type, XmlQualifiedName> |
| | 0 | 476 | | { |
| | 0 | 477 | | [typeof(sbyte)] = new XmlQualifiedName("byte", XmlSchema.Namespace), |
| | 0 | 478 | | [typeof(byte)] = new XmlQualifiedName("unsignedByte", XmlSchema.Namespace), |
| | 0 | 479 | | [typeof(short)] = new XmlQualifiedName("short", XmlSchema.Namespace), |
| | 0 | 480 | | [typeof(ushort)] = new XmlQualifiedName("unsignedShort", XmlSchema.Namespace), |
| | 0 | 481 | | [typeof(int)] = new XmlQualifiedName("int", XmlSchema.Namespace), |
| | 0 | 482 | | [typeof(uint)] = new XmlQualifiedName("unsignedInt", XmlSchema.Namespace), |
| | 0 | 483 | | [typeof(long)] = new XmlQualifiedName("long", XmlSchema.Namespace), |
| | 0 | 484 | | [typeof(ulong)] = new XmlQualifiedName("unsignedLong", XmlSchema.Namespace) |
| | 0 | 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 | | } |