private object CreateCollection(DataTypeDescriptor descriptor, int capacity, bool isCaseInsensitive, object comparer) { CreateInstanceAccessor ctor = GetInitializer(descriptor); if (CtorArguments == null) { return(ctor.CreateInstance()); } object[] parameters = new object[CtorArguments.Length]; for (int i = 0; i < CtorArguments.Length; i++) { switch (CtorArguments[i]) { case CollectionCtorArguments.Capacity: parameters[i] = capacity; break; case CollectionCtorArguments.Comparer: parameters[i] = comparer; break; case CollectionCtorArguments.CaseInsensitivity: parameters[i] = isCaseInsensitive; break; default: return(Throw.InternalError <object>($"Unsupported {nameof(CollectionCtorArguments)}")); } } return(ctor.CreateInstance(parameters)); }
private protected static bool TryDeserializeByConverter(MemberInfo member, Type memberType, Func <string> readStringValue, out object result) { TypeConverter converter = null; // Explicitly defined type converter if can convert from string Attribute[] attrs = Attribute.GetCustomAttributes(member, typeof(TypeConverterAttribute), true); if (attrs.Length > 0 && attrs[0] is TypeConverterAttribute convAttr && Reflector.ResolveType(convAttr.ConverterTypeName) is Type convType) { ConstructorInfo ctor = convType.GetConstructor(new Type[] { Reflector.Type }); object[] ctorParams = { memberType }; if (ctor == null) { ctor = convType.GetDefaultConstructor(); ctorParams = Reflector.EmptyObjects; } if (ctor != null) { converter = CreateInstanceAccessor.GetAccessor(ctor).CreateInstance(ctorParams) as TypeConverter; } } if (converter?.CanConvertFrom(Reflector.StringType) != true) { result = null; return(false); } result = converter.ConvertFromInvariantString(readStringValue.Invoke()); return(true); }
private protected static object CreateCollectionByInitializerCollection(ConstructorInfo collectionCtor, IEnumerable initializerCollection, Dictionary <MemberInfo, object> members) { initializerCollection = initializerCollection.AdjustInitializerCollection(collectionCtor); object result = CreateInstanceAccessor.GetAccessor(collectionCtor).CreateInstance(initializerCollection); // restoring fields and properties of the final collection foreach (KeyValuePair <MemberInfo, object> member in members) { var property = member.Key as PropertyInfo; var field = property != null ? null : member.Key as FieldInfo; // read-only property if (property?.CanWrite == false) { object existingValue = property.Get(result); if (property.PropertyType.IsValueType) { if (Equals(existingValue, member.Value)) { continue; } Throw.SerializationException(Res.XmlSerializationPropertyHasNoSetter(property.Name, collectionCtor.DeclaringType)); } if (existingValue == null && member.Value == null) { continue; } if (member.Value == null) { Throw.ReflectionException(Res.XmlSerializationPropertyHasNoSetterCantSetNull(property.Name, collectionCtor.DeclaringType)); } if (existingValue == null) { Throw.ReflectionException(Res.XmlSerializationPropertyHasNoSetterGetsNull(property.Name, collectionCtor.DeclaringType)); } if (existingValue.GetType() != member.Value.GetType()) { Throw.ArgumentException(Res.XmlSerializationPropertyTypeMismatch(collectionCtor.DeclaringType, property.Name, member.Value.GetType(), existingValue.GetType())); } CopyContent(member.Value, existingValue); continue; } // read-write property if (property != null) { property.Set(result, member.Value); continue; } // field field.Set(result, member.Value); } return(result); }
private CreateInstanceAccessor GetInitializer(DataTypeDescriptor descriptor) { CreateInstanceAccessor GetCtorAccessor(Type type) { if (CtorArguments == null) { return(CreateInstanceAccessor.GetAccessor(type)); } Type[] args = new Type[CtorArguments.Length]; for (int i = 0; i < CtorArguments.Length; i++) { switch (CtorArguments[i]) { case CollectionCtorArguments.Capacity: args[i] = Reflector.IntType; break; case CollectionCtorArguments.CaseInsensitivity: args[i] = Reflector.BoolType; break; case CollectionCtorArguments.Comparer: args[i] = IsGeneric ? HasEqualityComparer ? typeof(IEqualityComparer <>).GetGenericType(type.GetGenericArguments()[0]) : typeof(IComparer <>).GetGenericType(type.GetGenericArguments()[0]) : HasEqualityComparer ? typeof(IEqualityComparer) : typeof(IComparer); break; default: return(Throw.InternalError <CreateInstanceAccessor>($"Unsupported {nameof(CollectionCtorArguments)}")); } } ConstructorInfo ctor = type.GetConstructor(args); if (ctor == null) { Throw.InvalidOperationException(Res.ReflectionCtorNotFound(type)); } return(CreateInstanceAccessor.GetAccessor(ctor)); } if (ctorCache == null) { Interlocked.CompareExchange(ref ctorCache, new Cache <Type, CreateInstanceAccessor>(GetCtorAccessor).GetThreadSafeAccessor(), null); } return(ctorCache[descriptor.Type]); }
private static bool TryDeserializeObject(Type type, XmlReader reader, object existingInstance, out object result) { #region Local Methods to reduce complexity bool TryDeserializeKeyValue(ref TryDeserializeObjectContext ctx) { if (ctx.Type?.IsGenericTypeOf(Reflector.KeyValuePairType) != true) { return(false); } bool keyRead = false; bool valueRead = false; object key = null; object value = null; while (true) { ReadToNodeType(ctx.Reader, XmlNodeType.Element, XmlNodeType.EndElement); switch (ctx.Reader.NodeType) { case XmlNodeType.Element: switch (ctx.Reader.Name) { case nameof(KeyValuePair <_, _> .Key): if (keyRead) { Throw.ArgumentException(Res.XmlSerializationMultipleKeys); } keyRead = true; string attrType = ctx.Reader[XmlSerializer.AttributeType]; Type keyType = attrType != null?Reflector.ResolveType(attrType) : ctx.Type.GetGenericArguments()[0]; if (!TryDeserializeObject(keyType, ctx.Reader, null, out key)) { if (attrType != null && keyType == null) { Throw.ReflectionException(Res.XmlSerializationCannotResolveType(attrType)); } Throw.NotSupportedException(Res.XmlSerializationDeserializingTypeNotSupported(keyType)); } break; case nameof(KeyValuePair <_, _> .Value): if (valueRead) { Throw.ArgumentException(Res.XmlSerializationMultipleValues); } valueRead = true; attrType = ctx.Reader[XmlSerializer.AttributeType]; Type valueType = attrType != null?Reflector.ResolveType(attrType) : ctx.Type.GetGenericArguments()[1]; if (!TryDeserializeObject(valueType, ctx.Reader, null, out value)) { if (attrType != null && valueType == null) { Throw.ReflectionException(Res.XmlSerializationCannotResolveType(attrType)); } Throw.NotSupportedException(Res.XmlSerializationDeserializingTypeNotSupported(valueType)); } break; default: Throw.ArgumentException(Res.XmlSerializationUnexpectedElement(ctx.Reader.Name)); break; } break; case XmlNodeType.EndElement: // end of KeyValue: checking whether both key and value have been read if (!keyRead) { Throw.ArgumentException(Res.XmlSerializationKeyValueMissingKey); } if (!valueRead) { Throw.ArgumentException(Res.XmlSerializationKeyValueMissingValue); } ctx.Result = Activator.CreateInstance(ctx.Type); Accessors.SetKeyValue(ctx.Result, key, value); return(true); } } } void DeserializeBinary(ref TryDeserializeObjectContext ctx) { if (ctx.Reader.IsEmptyElement) { return; } string attrCrc = ctx.Reader[XmlSerializer.AttributeCrc]; ReadToNodeType(ctx.Reader, XmlNodeType.Text); byte[] data = Convert.FromBase64String(ctx.Reader.Value); if (attrCrc != null) { if (Crc32.CalculateHash(data).ToString("X8", CultureInfo.InvariantCulture) != attrCrc) { Throw.ArgumentException(Res.XmlSerializationCrcError); } } ctx.Result = BinarySerializer.Deserialize(data); ReadToNodeType(ctx.Reader, XmlNodeType.EndElement); } bool TryDeserializeComplexObject(ref TryDeserializeObjectContext ctx) { if (ctx.Type == null || ctx.Reader.IsEmptyElement) { return(false); } // 1.) array (both existing and new) if (ctx.Type.IsArray) { ctx.Result = DeserializeArray(ctx.ExistingInstance as Array, ctx.Type.GetElementType(), ctx.Reader, true); return(true); } // 2.) existing read-write collection if (ctx.Type.IsReadWriteCollection(ctx.ExistingInstance)) { DeserializeContent(ctx.Reader, ctx.ExistingInstance); ctx.Result = ctx.ExistingInstance; return(true); } bool isCollection = ctx.Type.IsSupportedCollectionForReflection(out var defaultCtor, out var collectionCtor, out var elementType, out bool isDictionary); // 3.) New collection by collectionCtor (only if there is no defaultCtor) if (isCollection && defaultCtor == null && !ctx.Type.IsValueType) { ctx.Result = DeserializeContentByInitializerCollection(ctx.Reader, collectionCtor, elementType, isDictionary); return(true); } ctx.Result = ctx.ExistingInstance ?? (ctx.Type.CanBeCreatedWithoutParameters() ? ctx.Type.IsValueType ? Activator.CreateInstance(ctx.Type) : CreateInstanceAccessor.GetAccessor(ctx.Type).CreateInstance() : Throw.ReflectionException <object>(Res.XmlSerializationNoDefaultCtor(ctx.Type))); // 4.) New collection by collectionCtor again (there IS defaultCtor but the new instance is read-only so falling back to collectionCtor) if (isCollection && !ctx.Type.IsReadWriteCollection(ctx.Result)) { if (collectionCtor != null) { ctx.Result = DeserializeContentByInitializerCollection(ctx.Reader, collectionCtor, elementType, isDictionary); return(true); } Throw.SerializationException(Res.XmlSerializationCannotDeserializeReadOnlyCollection(ctx.Type)); } // 5.) Newly created collection or any other object (both existing and new) DeserializeContent(ctx.Reader, ctx.Result); return(true); } #endregion // null value if (reader.IsEmptyElement && (type == null || !type.IsValueType || type.IsNullable())) { result = null; return(true); } if (type != null && type.IsNullable()) { type = Nullable.GetUnderlyingType(type); } // a.) If type can be natively parsed, parsing from string if (type != null && type.CanBeParsedNatively()) { string value = ReadStringValue(reader); result = value.Parse(type); return(true); } // b.) Deserialize IXmlSerializable string format = reader[XmlSerializer.AttributeFormat]; if (type != null && format == XmlSerializer.AttributeValueCustom) { object instance = existingInstance ?? (type.CanBeCreatedWithoutParameters() ? type.IsValueType ? Activator.CreateInstance(type) : CreateInstanceAccessor.GetAccessor(type).CreateInstance() : Throw.ReflectionException <object>(Res.XmlSerializationNoDefaultCtor(type))); if (!(instance is IXmlSerializable xmlSerializable)) { result = default; Throw.ArgumentException(Res.XmlSerializationNotAnIXmlSerializable(type)); return(default);
private static bool TryDeserializeObject(Type type, XElement element, object existingInstance, out object result) { #region Local Methods to reduce complexity bool TryDeserializeKeyValue(ref TryDeserializeObjectContext ctx) { if (ctx.Type?.IsGenericTypeOf(Reflector.KeyValuePairType) == true) { // key XElement xItem = ctx.Element.Element(nameof(KeyValuePair <_, _> .Key)); if (xItem == null) { Throw.ArgumentException(Res.XmlSerializationKeyValueMissingKey); } XAttribute xType = xItem.Attribute(XmlSerializer.AttributeType); Type keyType = xType != null?Reflector.ResolveType(xType.Value) : ctx.Type.GetGenericArguments()[0]; if (!TryDeserializeObject(keyType, xItem, null, out object key)) { if (xType != null && keyType == null) { Throw.ReflectionException(Res.XmlSerializationCannotResolveType(xType.Value)); } Throw.NotSupportedException(Res.XmlSerializationDeserializingTypeNotSupported(keyType)); } // value xItem = ctx.Element.Element(nameof(KeyValuePair <_, _> .Value)); if (xItem == null) { Throw.ArgumentException(Res.XmlSerializationKeyValueMissingValue); } xType = xItem.Attribute(XmlSerializer.AttributeType); Type valueType = xType != null?Reflector.ResolveType(xType.Value) : ctx.Type.GetGenericArguments()[1]; if (!TryDeserializeObject(valueType, xItem, null, out object value)) { if (xType != null && valueType == null) { Throw.ReflectionException(Res.XmlSerializationCannotResolveType(xType.Value)); } Throw.NotSupportedException(Res.XmlSerializationDeserializingTypeNotSupported(valueType)); } ctx.Result = Activator.CreateInstance(ctx.Type); Accessors.SetKeyValue(ctx.Result, key, value); return(true); } return(false); } void DeserializeBinary(ref TryDeserializeObjectContext ctx) { if (ctx.Element.IsEmpty) { return; } byte[] data = Convert.FromBase64String(ctx.Element.Value); XAttribute attrCrc = ctx.Element.Attribute(XmlSerializer.AttributeCrc); if (attrCrc != null) { if (Crc32.CalculateHash(data).ToString("X8", CultureInfo.InvariantCulture) != attrCrc.Value) { Throw.ArgumentException(Res.XmlSerializationCrcError); } } ctx.Result = BinarySerializer.Deserialize(data); } bool TryDeserializeComplexObject(ref TryDeserializeObjectContext ctx) { if (ctx.Type != null && !ctx.Element.IsEmpty) { // 1.) array (both existing and new) if (ctx.Type.IsArray) { ctx.Result = DeserializeArray(ctx.ExistingInstance as Array, ctx.Type.GetElementType(), ctx.Element, true); return(true); } // 2.) existing read-write collection if (ctx.Type.IsReadWriteCollection(ctx.ExistingInstance)) { DeserializeContent(ctx.Element, ctx.ExistingInstance); ctx.Result = ctx.ExistingInstance; return(true); } bool isCollection = ctx.Type.IsSupportedCollectionForReflection(out var defaultCtor, out var collectionCtor, out var elementType, out bool isDictionary); // 3.) New collection by collectionCtor (only if there is no defaultCtor) if (isCollection && defaultCtor == null && !ctx.Type.IsValueType) { ctx.Result = DeserializeContentByInitializerCollection(ctx.Element, collectionCtor, elementType, isDictionary); return(true); } ctx.Result = ctx.ExistingInstance ?? (ctx.Type.CanBeCreatedWithoutParameters() ? ctx.Type.IsValueType ? Activator.CreateInstance(ctx.Type) : CreateInstanceAccessor.GetAccessor(ctx.Type).CreateInstance() : Throw.ReflectionException <object>(Res.XmlSerializationNoDefaultCtor(ctx.Type))); // 4.) New collection by collectionCtor again (there IS defaultCtor but the new instance is read-only so falling back to collectionCtor) if (isCollection && !ctx.Type.IsReadWriteCollection(ctx.Result)) { if (collectionCtor != null) { ctx.Result = DeserializeContentByInitializerCollection(ctx.Element, collectionCtor, elementType, isDictionary); return(true); } Throw.SerializationException(Res.XmlSerializationCannotDeserializeReadOnlyCollection(ctx.Type)); } // 5.) Newly created collection or any other object (both existing and new) DeserializeContent(ctx.Element, ctx.Result); return(true); } return(false); } #endregion // null value if (element.IsEmpty && (type == null || !type.IsValueType || type.IsNullable())) { result = null; return(true); } if (type != null && type.IsNullable()) { type = Nullable.GetUnderlyingType(type); } // a.) If type can be natively parsed, parsing from string if (type != null && type.CanBeParsedNatively()) { string value = ReadStringValue(element); result = value.Parse(type); return(true); } // b.) Deserialize IXmlSerializable string format = element.Attribute(XmlSerializer.AttributeFormat)?.Value; if (type != null && format == XmlSerializer.AttributeValueCustom) { object instance = existingInstance ?? (type.CanBeCreatedWithoutParameters() ? type.IsValueType ? Activator.CreateInstance(type) : CreateInstanceAccessor.GetAccessor(type).CreateInstance() : Throw.ReflectionException <object>(Res.XmlSerializationNoDefaultCtor(type))); if (!(instance is IXmlSerializable xmlSerializable)) { result = default; Throw.ArgumentException(Res.XmlSerializationNotAnIXmlSerializable(type)); return(default);