ReflectionCache
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 ReflectionExtensions.GetValue((PropertyInfo)MemberInfo, obj);
return ((FieldInfo)MemberInfo).GetValue(obj);
}
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.GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(delegate(PropertyInfo p) {
if (!(p.GetGetMethod(true)?.IsAssembly ?? false) && !(p.GetGetMethod(true)?.IsPublic ?? false) && !(p.GetSetMethod(true)?.IsAssembly ?? false))
return p.GetSetMethod(true)?.IsPublic ?? false;
return true;
});
List<PropertyOrField> value = (from p in Enumerable.Concat(second: type.GetTypeInfo().GetFields(BindingFlags.Instance | BindingFlags.Public), 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 property.GetCustomAttributes(true).OfType<Attribute>()) {
if (item is JsonIgnoreAttribute)
jsonIgnoreAttribute = (item as JsonIgnoreAttribute);
else if (item is JsonPropertyAttribute) {
jsonPropertyAttribute = (item as JsonPropertyAttribute);
} else if (item.GetType().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 = ReflectionExtensions.GetCustomAttributes(type.GetTypeInfo(), true).SingleOrDefault((Attribute a) => a.GetType().Name == "DataContractAttribute");
DataContractAttributeCacheByType[type] = value;
}
return DataContractAttributeCacheByType[type];
}
}
}
}