diff --git a/Marr.Data/Reflection/CachedReflectionStrategy.cs b/Marr.Data/Reflection/CachedReflectionStrategy.cs index 2b4be4b76..a19eff03d 100644 --- a/Marr.Data/Reflection/CachedReflectionStrategy.cs +++ b/Marr.Data/Reflection/CachedReflectionStrategy.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Reflection; using Fasterflect; @@ -6,13 +7,26 @@ namespace Marr.Data.Reflection { public class CachedReflectionStrategy : IReflectionStrategy { + private static readonly Dictionary MemberCache = new Dictionary(); + private static MemberInfo GetMember(Type entityType, string name) + { + MemberInfo member; + var key = entityType.FullName + name; + if (!MemberCache.TryGetValue(key, out member)) + { + member = entityType.GetMember(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)[0]; + MemberCache[key] = member; + } + + return member; + } /// /// Sets an entity field value by name to the passed in 'val'. /// public void SetFieldValue(T entity, string fieldName, object val) { - MemberInfo member = entity.GetType().GetMember(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)[0]; + MemberInfo member = GetMember(entity.GetType(), fieldName); try { @@ -56,7 +70,8 @@ public void SetFieldValue(T entity, string fieldName, object val) /// public object GetFieldValue(object entity, string fieldName) { - MemberInfo member = entity.GetType().GetMember(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)[0]; + MemberInfo member = GetMember(entity.GetType(), fieldName); + if (member.MemberType == MemberTypes.Field) { diff --git a/NzbDrone.Core/Datastore/DbFactory.cs b/NzbDrone.Core/Datastore/DbFactory.cs index 40ed7965e..bb7a8ad43 100644 --- a/NzbDrone.Core/Datastore/DbFactory.cs +++ b/NzbDrone.Core/Datastore/DbFactory.cs @@ -33,7 +33,7 @@ public IDatabase Create(string dbPath, MigrationType migrationType = MigrationTy _migrationController.MigrateToLatest(connectionString, migrationType); - MapRepository.Instance.ReflectionStrategy = new SimpleReflectionStrategy(); + MapRepository.Instance.ReflectionStrategy = new DelegateReflectionStrategy(); return new Database(() => { diff --git a/NzbDrone.Core/Datastore/DelegateReflectionStrategy.cs b/NzbDrone.Core/Datastore/DelegateReflectionStrategy.cs new file mode 100644 index 000000000..6bff4fc68 --- /dev/null +++ b/NzbDrone.Core/Datastore/DelegateReflectionStrategy.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; +using Marr.Data.Reflection; + +namespace NzbDrone.Core.Datastore +{ + public class DelegateReflectionStrategy : IReflectionStrategy + { + private static readonly Dictionary SetterCache = new Dictionary(); + private static readonly Dictionary GetterCache = new Dictionary(); + + private static PropertySetterDelegate SetterFunction(Type entityType, string name) + { + PropertySetterDelegate setter; + var key = string.Concat(entityType.FullName, name); + if (!SetterCache.TryGetValue(key, out setter)) + { + var setterMember = entityType.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + setter = setterMember.GetPropertySetterFn(); + SetterCache[key] = setter; + } + + return setter; + } + + + private static PropertyGetterDelegate GetterFunction(Type entityType, string name) + { + PropertyGetterDelegate getter; + var key = string.Concat(entityType.FullName, name); + if (!GetterCache.TryGetValue(key, out getter)) + { + var propertyInfo = entityType.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + getter = propertyInfo.GetPropertyGetterFn(); + GetterCache[key] = getter; + } + + return getter; + } + + + public void SetFieldValue(T entity, string fieldName, object val) + { + SetterFunction(entity.GetType(), fieldName)(entity, val); + } + + public object GetFieldValue(object entity, string fieldName) + { + return GetterFunction(entity.GetType(), fieldName); + } + + public object CreateInstance(Type type) + { + return Activator.CreateInstance(type); + } + + + + } + + public delegate void PropertySetterDelegate(object instance, object value); + public delegate object PropertyGetterDelegate(object instance); + + public static class PropertyInvoker + { + public static PropertySetterDelegate GetPropertySetterFn(this PropertyInfo propertyInfo) + { + var propertySetMethod = propertyInfo.GetSetMethod(); + if (propertySetMethod == null) return null; + +#if NO_EXPRESSIONS + return (o, convertedValue) => + { + propertySetMethod.Invoke(o, new[] { convertedValue }); + return; + }; +#else + var instance = Expression.Parameter(typeof(object), "i"); + var argument = Expression.Parameter(typeof(object), "a"); + + var instanceParam = Expression.Convert(instance, propertyInfo.DeclaringType); + var valueParam = Expression.Convert(argument, propertyInfo.PropertyType); + + var setterCall = Expression.Call(instanceParam, propertyInfo.GetSetMethod(), valueParam); + + return Expression.Lambda(setterCall, instance, argument).Compile(); +#endif + } + + public static PropertyGetterDelegate GetPropertyGetterFn(this PropertyInfo propertyInfo) + { + var getMethodInfo = propertyInfo.GetGetMethod(); + if (getMethodInfo == null) return null; + +#if NO_EXPRESSIONS + return o => propertyInfo.GetGetMethod().Invoke(o, new object[] { }); +#else + try + { + var oInstanceParam = Expression.Parameter(typeof(object), "oInstanceParam"); + var instanceParam = Expression.Convert(oInstanceParam, propertyInfo.DeclaringType); + + var exprCallPropertyGetFn = Expression.Call(instanceParam, getMethodInfo); + var oExprCallPropertyGetFn = Expression.Convert(exprCallPropertyGetFn, typeof(object)); + + var propertyGetFn = Expression.Lambda + ( + oExprCallPropertyGetFn, + oInstanceParam + ).Compile(); + + return propertyGetFn; + + } + catch (Exception ex) + { + Console.Write(ex.Message); + throw; + } +#endif + } + } + + +} \ No newline at end of file diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 20ef8261e..412d9adc8 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -220,6 +220,7 @@ +