ReflectionCache
Provides cached reflection APIs for better performance.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace NJsonSchema.Infrastructure
{
public static class ReflectionCache
{
public class PropertyOrField
{
public MemberInfo MemberInfo { get; }
public CustomAttributes CustomAttributes { get; }
public bool CanRead => (MemberInfo as PropertyInfo)?.CanRead ?? true;
public bool IsIndexer {
get {
if (MemberInfo is PropertyInfo)
return ((PropertyInfo)MemberInfo).GetIndexParameters().Length != 0;
return false;
}
}
public PropertyOrField(MemberInfo memberInfo, CustomAttributes customAttributes)
{
MemberInfo = memberInfo;
CustomAttributes = customAttributes;
}
public object GetValue(object obj)
{
if (MemberInfo is PropertyInfo)
return ((PropertyInfo)MemberInfo).GetValue(obj);
return ((FieldInfo)MemberInfo).GetValue(obj);
}
public void SetValue(object obj, object value)
{
if (MemberInfo is PropertyInfo)
((PropertyInfo)MemberInfo).SetValue(obj, value);
else
((FieldInfo)MemberInfo).SetValue(obj, value);
}
public string GetName()
{
if (CustomAttributes.JsonPropertyAttribute != null && !string.IsNullOrEmpty(CustomAttributes.JsonPropertyAttribute.PropertyName))
return CustomAttributes.JsonPropertyAttribute.PropertyName;
if (CustomAttributes.DataContractAttribute != null) {
dynamic val = CustomAttributes.DataMemberAttribute != null;
if ((val ? false : true) ? val : (val & !string.IsNullOrEmpty(CustomAttributes.DataMemberAttribute.Name)))
return (string)CustomAttributes.DataMemberAttribute.Name;
}
return MemberInfo.Name;
}
}
public class CustomAttributes
{
public JsonIgnoreAttribute JsonIgnoreAttribute { get; }
public JsonPropertyAttribute JsonPropertyAttribute { get; }
public Attribute DataContractAttribute { get; }
public dynamic DataMemberAttribute { get; }
public CustomAttributes(JsonIgnoreAttribute jsonIgnoreAttribute, JsonPropertyAttribute jsonPropertyAttribute, Attribute dataContractAttribute, Attribute dataMemberAttribute)
{
JsonIgnoreAttribute = jsonIgnoreAttribute;
JsonPropertyAttribute = jsonPropertyAttribute;
DataContractAttribute = dataContractAttribute;
DataMemberAttribute = dataMemberAttribute;
}
}
private static readonly Dictionary<Type, IList<PropertyOrField>> PropertyCacheByType = new Dictionary<Type, IList<PropertyOrField>>();
private static readonly Dictionary<Type, Attribute> DataContractAttributeCacheByType = new Dictionary<Type, Attribute>();
public static IEnumerable<PropertyOrField> GetPropertiesAndFields(Type type)
{
lock (PropertyCacheByType) {
if (!PropertyCacheByType.ContainsKey(type)) {
IEnumerable<PropertyInfo> source = type.GetRuntimeProperties().Where(delegate(PropertyInfo p) {
MethodInfo getMethod = p.GetMethod;
if ((object)getMethod == null)
return true;
return !getMethod.IsStatic;
});
List<PropertyOrField> value = (from p in Enumerable.Concat(second: type.GetRuntimeFields().Where(delegate(FieldInfo f) {
if (f.IsPublic)
return !f.IsStatic;
return false;
}), first: source.OfType<MemberInfo>())
select new PropertyOrField(p, GetCustomAttributes(p))).ToList();
PropertyCacheByType[type] = value;
}
return PropertyCacheByType[type];
}
}
private static CustomAttributes GetCustomAttributes(MemberInfo property)
{
JsonIgnoreAttribute jsonIgnoreAttribute = null;
JsonPropertyAttribute jsonPropertyAttribute = null;
Attribute dataMemberAttribute = null;
foreach (Attribute item in CustomAttributeExtensions.GetCustomAttributes(property, true).OfType<Attribute>()) {
if (item is JsonIgnoreAttribute)
jsonIgnoreAttribute = (item as JsonIgnoreAttribute);
else if (item is JsonPropertyAttribute) {
jsonPropertyAttribute = (item as JsonPropertyAttribute);
} else if (item.GetType().get_Name() == "DataMemberAttribute") {
dataMemberAttribute = item;
}
}
return new CustomAttributes(jsonIgnoreAttribute, jsonPropertyAttribute, GetDataContractAttribute(property.DeclaringType), dataMemberAttribute);
}
public static Attribute GetDataContractAttribute(Type type)
{
lock (DataContractAttributeCacheByType) {
if (!DataContractAttributeCacheByType.ContainsKey(type)) {
Attribute value = type.GetTypeInfo().GetCustomAttributes().SingleOrDefault((Attribute a) => a.GetType().get_Name() == "DataContractAttribute");
DataContractAttributeCacheByType[type] = value;
}
return DataContractAttributeCacheByType[type];
}
}
}
}