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);
}
}
}
}