using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; namespace Flurl.Util { public static class CommonExtensions { /// /// Converts an object's public properties to a collection of string-based key-value pairs. If the object happens /// to be an IDictionary, the IDictionary's keys and values converted to strings and returned. /// /// The object to parse into key-value pairs /// public static IEnumerable> ToKeyValuePairs(this object obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); return (obj is string) ? QueryParamCollection.Parse((string)obj) : (obj is IEnumerable) ? CollectionToKV((IEnumerable)obj) : ObjectToKV(obj); } /// /// Returns a string that represents the current object, using CultureInfo.InvariantCulture where possible. /// public static string ToInvariantString(this object obj) { // inspired by: http://stackoverflow.com/a/19570016/62600 var c = obj as IConvertible; if (c != null) return c.ToString(CultureInfo.InvariantCulture); var f = obj as IFormattable; return f?.ToString(null, CultureInfo.InvariantCulture) ?? obj.ToString(); } private static IEnumerable> ObjectToKV(object obj) { return from prop in obj.GetType().GetProperties() let val = prop.GetValue(obj, null) select new KeyValuePair(prop.Name, val); } private static IEnumerable> CollectionToKV(IEnumerable col) { // Accepts KeyValuePairs or any aribitray types that contain a property called "Key" or "Name" and a property called "Value". foreach (var item in col) { if (item == null) continue; var type = item.GetType(); var keyProp = type.GetProperty("Key") ?? type.GetProperty("key") ?? type.GetProperty("Name") ?? type.GetProperty("name"); if (keyProp == null) throw new ArgumentException("Cannot parse " + type.Name + " to key-value pair. Type must contain a property called 'Key' or 'Name'."); var valProp = type.GetProperty("Value") ?? type.GetProperty("value"); if (valProp == null) throw new ArgumentException("Cannot parse " + type.Name + " to key-value pair. Type must contain a property called 'Value'."); var key = keyProp.GetValue(item, null); if (key == null) continue; var val = valProp.GetValue(item, null); yield return new KeyValuePair(key.ToInvariantString(), val); } } } }