Make RequestParameters work for RT and perf

Around an 80% perf improvement
This commit is contained in:
Haacked
2013-10-27 20:31:46 -07:00
parent fbe0be1220
commit f6aa28f818
5 changed files with 136 additions and 54 deletions
+86 -51
View File
@@ -14,74 +14,109 @@ namespace Octokit
/// </summary>
public abstract class RequestParameters
{
static readonly ConcurrentDictionary<Type, List<PropertyInfo>> _propertiesMap =
new ConcurrentDictionary<Type, List<PropertyInfo>>();
static readonly ConcurrentDictionary<Type, List<PropertyParameter>> _propertiesMap =
new ConcurrentDictionary<Type, List<PropertyParameter>>();
public virtual IDictionary<string, string> ToParametersDictionary()
{
var properties = _propertiesMap.GetOrAdd(GetType(), GetPropertiesForType);
return (from property in properties
let value = GetValue(property)
let key = GetKey(property)
where value != null
select new { key, value }).ToDictionary(kvp => kvp.key, kvp => kvp.value);
var map = _propertiesMap.GetOrAdd(GetType(), GetPropertyParametersForType);
return (from property in map
let value = property.GetValue(this)
let key = property.Key
where value != null
select new { key, value }).ToDictionary(kvp => kvp.key, kvp => kvp.value);
}
static List<PropertyInfo> GetPropertiesForType(Type type)
static List<PropertyParameter> GetPropertyParametersForType(Type type)
{
return type.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList();
return type.GetAllProperties()
.Select(p => new PropertyParameter(p))
.ToList();
}
[SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase",
Justification = "GitHub API depends on lower case strings")]
static string GetKey(PropertyInfo property)
static Func<PropertyInfo, object, string> GetValueFunc(Type propertyType)
{
var attribute = property.GetCustomAttributes(typeof(ParameterAttribute), false)
.Cast<ParameterAttribute>()
.FirstOrDefault(attr => attr.Key != null);
return attribute == null
? property.Name.ToLowerInvariant()
: attribute.Key;
}
[SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase",
Justification = "GitHub API depends on lower case strings")]
string GetValue(PropertyInfo property)
{
var value = property.GetValue(this, null);
if (typeof(IEnumerable<string>).IsAssignableFrom(property.PropertyType))
if (typeof(IEnumerable<string>).IsAssignableFrom(propertyType))
{
var list = (IEnumerable<string>)value;
return !list.Any() ? null : String.Join(",", list);
}
if (property.PropertyType.IsDateTimeOffset() && value != null)
{
return ((DateTimeOffset)value).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ",
CultureInfo.InvariantCulture);
}
if (property.PropertyType.IsEnum && value != null)
{
var member = property.PropertyType.GetMember(value.ToString()).FirstOrDefault();
if (member != null)
return (prop, value) =>
{
var attribute = member.GetCustomAttributes(typeof(ParameterAttribute), false)
.Cast<ParameterAttribute>()
.FirstOrDefault();
if (attribute != null)
{
return attribute.Value;
}
}
var list = ((IEnumerable<string>)value).ToArray();
return !list.Any() ? null : String.Join(",", list);
};
}
return value != null
if (propertyType.IsDateTimeOffset())
{
return (prop, value) =>
{
if (value == null) return null;
return ((DateTimeOffset)value).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ",
CultureInfo.InvariantCulture);
};
}
if (propertyType.IsEnumeration())
{
var enumToAttributeDictionary = Enum.GetNames(propertyType)
.ToDictionary(name => name, name => GetParameterAttributeValueForEnumName(propertyType, name));
return (prop, value) =>
{
if (value == null) return null;
string attributeValue;
return enumToAttributeDictionary.TryGetValue(value.ToString(), out attributeValue)
? attributeValue ?? value.ToString().ToLowerInvariant()
: value.ToString().ToLowerInvariant();
};
}
return (prop, value) => value != null
? value.ToString().ToLowerInvariant()
: null;
}
static string GetParameterAttributeValueForEnumName(Type enumType, string name)
{
var member = enumType.GetMember(name).FirstOrDefault();
if (member == null) return null;
var attribute = member.GetCustomAttributes(typeof(ParameterAttribute), false)
.Cast<ParameterAttribute>()
.FirstOrDefault();
return attribute != null ? attribute.Value : null;
}
class PropertyParameter
{
readonly Func<PropertyInfo, object, string> _valueFunc;
readonly PropertyInfo _property;
public PropertyParameter(PropertyInfo property)
{
_property = property;
Key = GetParameterKeyFromProperty(property);
_valueFunc = GetValueFunc(property.PropertyType);
}
public string Key { get; private set; }
public string GetValue(object instance)
{
return _valueFunc(_property, _property.GetValue(instance, null));
}
[SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase",
Justification = "GitHub API depends on lower case strings")]
static string GetParameterKeyFromProperty(PropertyInfo property)
{
var attribute = property.GetCustomAttributes(typeof(ParameterAttribute), false)
.Cast<ParameterAttribute>()
.FirstOrDefault(attr => attr.Key != null);
return attribute == null
? property.Name.ToLowerInvariant()
: attribute.Key;
}
}
}
}