internal static object CreateDeserializationTarget(Type objectType, out IValueContainer valueContainer) { if (objectType == null || objectType == typeof(IValueContainer)) { valueContainer = new ValueContainer.ValueContainer(); return(valueContainer); } object target = Activator.CreateInstance(objectType); if (typeof(IValueContainer).IsAssignableFrom(objectType)) { valueContainer = (IValueContainer)target; } else { valueContainer = ValueContainerFactory.CreateProxy(target); } return(target); }
public void OnValueEnd() { if (_scope.ParentScope != null && _scope.ParentScope.Composer == null && _scope.ParentScope.Container == null) { _scope.ParentScope.IsDynamicContainer = true; } if (!_scope.ValueReceived && _scope.Composer != null) { _scope.Value = _scope.Composer.Compose(_scope.Container, _scope.Type); _scope.ValueReceived = true; } if (!_scope.ValueReceived && _scope.IsDynamicContainer) { _scope.Value = _scope.Container; _scope.ValueReceived = true; } if (!_scope.ValueReceived && !_scope.ValueInfo.IsCollection && _scope.Container == null) { if (_scope.ValueInfo.ReferenceId.HasValue) { if (!_objectByIdMap.TryGetValue(_scope.ValueInfo.ReferenceId.Value, out _scope.Value)) { throw new InvalidOperationException($"Could not find object by ID '{_scope.ValueInfo.ReferenceId.Value}'."); } _scope.ValueReceived = true; } else if (_scope.ValueInfo.SpecialId != null) { if (_objectByNameMap == null || !_objectByNameMap.TryGetValue(_scope.ValueInfo.SpecialId, out _scope.Value)) { throw new InvalidOperationException($"Could not find object by ID '{_scope.ValueInfo.SpecialId}'."); } _scope.ValueReceived = true; } } var valueScope = _scope; _scope = _scope.ParentScope; if (valueScope.ValueReceived && _scope != null) { var value = valueScope.Value; #warning Support various collection types. Currently supports arrays only. if (valueScope.ValueInfo.IsCollection) { value = this.GetType() .GetMethod(nameof(ToArray), BindingFlags.Static | BindingFlags.NonPublic) .MakeGenericMethod(value.GetType().GetGenericArguments()[0]) .Invoke(null, new object[] { value }); } Type targetType; if (_scope.ValueInfo.IsCollection) { targetType = _scope.ItemType; } else if (_scope.IsDynamicContainer) { targetType = value?.GetType(); } else { var startIndex = _scope.Index + 1; _scope.Index = FindIndex(_scope.Container, valueScope.ValueInfo.Name, startIndex); // Try to find by value type if the argument was renamed. if (_scope.Index < 0 && value != null) { _scope.Index = FindIndex(_scope.Container, value.GetType()); } if (_scope.Index >= 0) { targetType = _scope.Container.GetType(_scope.Index); } else { // TODO: better skip logic? value = null; targetType = null; _scope.Index = startIndex - 1; } } if (value != null && targetType != null) { value = EnsureValueType(targetType, value); if (valueScope.ValueInfo.ReferenceId.HasValue) { _objectByIdMap[valueScope.ValueInfo.ReferenceId.Value] = value; } if (_scope.ValueInfo.IsCollection) { _scope.Array.Add(value); } else if (_scope.IsDynamicContainer) { var dynamicContainer = _scope.Container as ValueContainer.ValueContainer; if (dynamicContainer == null) { dynamicContainer = new ValueContainer.ValueContainer(); _scope.Container = dynamicContainer; } dynamicContainer.Add(valueScope.ValueInfo.Name, targetType, value); } else { _scope.Container.SetValue(_scope.Index, value); } } } }
public void OnValueEnd() { if (_scope.ParentScope != null && _scope.ParentScope.Composer == null && _scope.ParentScope.Container == null) { _scope.ParentScope.IsDynamicContainer = true; } if (!_scope.ValueReceived && _scope.Composer != null) { _scope.Value = _scope.Composer.Compose(_scope.Container, _scope.Type); _scope.ValueReceived = true; } if (!_scope.ValueReceived && _scope.IsDynamicContainer) { _scope.Value = _scope.Container; _scope.ValueReceived = true; } if (!_scope.ValueReceived) { if (_scope.ValueInfo.ReferenceId.HasValue) { if (!_objectByIdMap.TryGetValue(_scope.ValueInfo.ReferenceId.Value, out _scope.Value)) { throw new InvalidOperationException($"Could not find object by ID '{_scope.ValueInfo.ReferenceId.Value}'."); } _scope.ValueReceived = true; } else if (_scope.ValueInfo.SpecialId != null) { if (_objectByNameMap == null || !_objectByNameMap.TryGetValue(_scope.ValueInfo.SpecialId, out _scope.Value)) { throw new InvalidOperationException($"Could not find object by ID '{_scope.ValueInfo.SpecialId}'."); } _scope.ValueReceived = true; } } var valueScope = _scope; _scope = _scope.ParentScope; if (valueScope.ValueReceived) { var value = valueScope.Value; #warning Support various collection types. Currently supports arrays only. if (valueScope.ValueInfo.IsCollection) { value = this.GetType() .GetMethod(nameof(ToArray), BindingFlags.Static | BindingFlags.NonPublic) .MakeGenericMethod(value.GetType().GetGenericArguments()[0]) .Invoke(null, new object[] { value }); } Type targetType; if (_scope.ValueInfo.IsCollection) { targetType = _scope.ItemType; } else if (_scope.IsDynamicContainer) { targetType = value?.GetType(); } else { _scope.Index = FindIndex(_scope.Container, valueScope.ValueInfo.Name, _scope.Index + 1); if (_scope.Index >= 0) { targetType = _scope.Container.GetType(_scope.Index); } else { // TODO: better skip logic? value = null; targetType = null; } } if (value != null && targetType != null) { // TODO: converter if (!targetType.IsAssignableFrom(value.GetType())) { if (targetType.IsArray || ((value is IList) && targetType == typeof(object))) { #warning This byte[] conversion is a quick-fix. Do it properly by adding type during serialization? if (targetType == typeof(byte[]) && value is string) { value = Convert.FromBase64String((string)value); } else { value = this.GetType() .GetMethod(nameof(ToArray), BindingFlags.Static | BindingFlags.NonPublic) .MakeGenericMethod(targetType.GetElementType() ?? value.GetType().GetGenericArguments()[0]) .Invoke(null, new object[] { value }); } } else if (targetType.IsEnum()) { value = Enum.ToObject(targetType, value); } else if (targetType == typeof(Guid) && value is string strGuid) { value = Guid.Parse(strGuid); } else if (targetType is Type && value is TypeSerializationInfo typeInfo) { value = ResolveType(typeInfo); } else { value = Convert.ChangeType(value, targetType); } } if (valueScope.ValueInfo.ReferenceId.HasValue) { _objectByIdMap[valueScope.ValueInfo.ReferenceId.Value] = value; } if (_scope.ValueInfo.IsCollection) { _scope.Array.Add(value); } else if (_scope.IsDynamicContainer) { var dynamicContainer = _scope.Container as ValueContainer.ValueContainer; if (dynamicContainer == null) { dynamicContainer = new ValueContainer.ValueContainer(); _scope.Container = dynamicContainer; } dynamicContainer.Add(valueScope.ValueInfo.Name, targetType, value); } else { _scope.Container.SetValue(_scope.Index, value); } } } }