public static object ToFieldValue(this NSObject fieldValue, Type type) { if (fieldValue == null) { return(null); } switch (fieldValue) { case NSNumber number: if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable <>)) { type = type.GenericTypeArguments[0]; } if (type == typeof(bool)) { return(number.BoolValue); } if (type == typeof(byte)) { return(number.ByteValue); } if (type == typeof(double)) { return(number.DoubleValue); } if (type == typeof(float)) { return(number.FloatValue); } if (type == typeof(int)) { return(number.Int32Value); } if (type == typeof(long)) { return(number.Int64Value); } if (type == typeof(sbyte)) { return(number.SByteValue); } if (type == typeof(short)) { return(number.Int16Value); } if (type == typeof(uint)) { return(number.UInt32Value); } if (type == typeof(ulong)) { return(number.UInt64Value); } if (type == typeof(ushort)) { return(number.UInt16Value); } return(Convert.ChangeType(number.DoubleValue, type)); case NSString @string: return(@string.ToString()); case Firebase.CloudFirestore.Timestamp timestamp: { var time = new Timestamp(timestamp); if (type == typeof(DateTime) || type == typeof(DateTime?)) { return(time.ToDateTime()); } if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?)) { return(time.ToDateTimeOffset()); } return(time); } case NSDate date: { var time = new Timestamp(date); if (type == typeof(DateTime) || type == typeof(DateTime?)) { return(time.ToDateTime()); } if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?)) { return(time.ToDateTimeOffset()); } return(time); } case NSArray array: { IList list; if (type.GetInterfaces().Contains(typeof(IList))) { list = (IList)Activator.CreateInstance(type); } else if (type.IsGenericType) { var listType = typeof(List <>).MakeGenericType(type.GenericTypeArguments[0]); list = (IList)Activator.CreateInstance(listType); } else { list = new List <object>(); } var genericType = typeof(object); if (type.IsGenericType) { genericType = type.GenericTypeArguments[0]; } for (nuint i = 0; i < array.Count; i++) { list.Add(array.GetItem <NSObject>(i).ToFieldValue(genericType)); } return(list); } case NSDictionary dictionary: { object @object; if (type == typeof(object)) { @object = new Dictionary <string, object>(); } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary <,>)) { var dictionaryType = typeof(Dictionary <,>).MakeGenericType(type.GenericTypeArguments[0], type.GenericTypeArguments[1]); @object = Activator.CreateInstance(dictionaryType); } else { @object = Activator.CreateInstance(type); } if (@object is IDictionary dict) { var genericType = typeof(object); if (type.IsGenericType) { genericType = type.GenericTypeArguments[1]; } foreach (var(key, value) in dictionary) { dict.Add(key.ToString(), value.ToFieldValue(genericType)); } } else { var properties = type.GetProperties(); var mappedProperties = properties.Select(p => (Property: p, Attribute: Attribute.GetCustomAttribute(p, typeof(MapToAttribute)) as MapToAttribute)) .Where(t => t.Attribute != null) .ToDictionary(t => t.Attribute.Mapping, t => t.Property); var igonoredProperties = properties.Where(p => Attribute.GetCustomAttribute(p, typeof(IgnoredAttribute)) != null); foreach (var(key, value) in dictionary) { PropertyInfo property; if (mappedProperties.ContainsKey(key.ToString())) { property = mappedProperties[key.ToString()]; } else { property = type.GetProperty(key.ToString()); } if (property != null && !igonoredProperties.Contains(property)) { property.SetValue(@object, value.ToFieldValue(property.PropertyType)); } } } return(@object); } case NSData data: if (type == typeof(byte[])) { return(data.ToArray()); } return(new MemoryStream(data.ToArray())); case Firebase.CloudFirestore.GeoPoint geoPoint: return(new GeoPoint(geoPoint)); case Firebase.CloudFirestore.DocumentReference documentReference: return(new DocumentReferenceWrapper(documentReference)); case NSNull @null: return(null); default: throw new ArgumentOutOfRangeException($"{fieldValue.GetType().FullName} is not supported"); } }