Removed boxing in TweenMemberss getters and setters (#1002)

* Removed boxing in TweenMemberss getters and setters

* Removed unnecessary inclusions and comments

* Simplified the get method creation on @AristurtleDev 's suggestion
This commit is contained in:
Diego García
2025-07-30 13:24:43 -05:00
committed by GitHub
parent 393ba13013
commit 33580aaaac
3 changed files with 41 additions and 35 deletions
@@ -2,43 +2,45 @@ using System;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.VisualBasic;
namespace MonoGame.Extended.Tweening
{
public sealed class TweenFieldMember<T> : TweenMember<T>
where T : struct
where T : struct
{
private readonly FieldInfo _fieldInfo;
public TweenFieldMember(object target, FieldInfo fieldInfo)
public TweenFieldMember(object target, FieldInfo fieldInfo)
: base(target, CompileGetMethod(fieldInfo), CompileSetMethod(fieldInfo))
{
_fieldInfo = fieldInfo;
}
private static Func<object, object> CompileGetMethod(FieldInfo fieldInfo)
private static Func<object, T> CompileGetMethod(FieldInfo fieldInfo)
{
var self = Expression.Parameter(typeof(object));
var instance = Expression.Convert(self, fieldInfo.DeclaringType);
var field = Expression.Field(instance, fieldInfo);
var convert = Expression.TypeAs(field, typeof(object));
return Expression.Lambda<Func<object, object>>(convert, self).Compile();
var entityType = fieldInfo.DeclaringType!;
var parameter = Expression.Parameter(typeof(object), "entity");
var property = Expression.Field(Expression.Convert(parameter, entityType), fieldInfo);
return Expression.Lambda<Func<object, T>>(property, parameter).Compile();
}
private static Action<object, object> CompileSetMethod(FieldInfo fieldInfo)
private static Action<object, T> CompileSetMethod(FieldInfo fieldInfo)
{
Debug.Assert(fieldInfo.DeclaringType != null);
var self = Expression.Parameter(typeof(object));
var value = Expression.Parameter(typeof(object));
var fieldExp = Expression.Field(Expression.Convert(self, fieldInfo.DeclaringType), fieldInfo);
var assignExp = Expression.Assign(fieldExp, Expression.Convert(value, fieldInfo.FieldType));
var entityType = fieldInfo.DeclaringType!;
var targetParam = Expression.Parameter(typeof(object), "target");
var valueParam = Expression.Parameter(typeof(T), "value");
var conversion = Expression.Convert(targetParam, entityType);
return Expression.Lambda<Action<object, object>>(assignExp, self, value).Compile();
var field = Expression.Field(conversion, fieldInfo);
var assignation = Expression.Assign(field, valueParam);
return Expression.Lambda<Action<object, T>>(assignation, targetParam, valueParam).Compile();
}
public override Type Type => _fieldInfo.FieldType;
public override string Name => _fieldInfo.Name;
}
}
}
@@ -18,19 +18,19 @@ namespace MonoGame.Extended.Tweening
public abstract class TweenMember<T> : TweenMember
where T : struct
{
protected TweenMember(object target, Func<object, object> getMethod, Action<object, object> setMethod)
protected TweenMember(object target, Func<object, T> getMethod, Action<object, T> setMethod)
: base(target)
{
_getMethod = getMethod;
_setMethod = setMethod;
}
private readonly Func<object, object> _getMethod;
private readonly Action<object, object> _setMethod;
private readonly Func<object, T> _getMethod;
private readonly Action<object, T> _setMethod;
public T Value
{
get { return (T) _getMethod(Target); }
get { return _getMethod(Target); }
set { _setMethod(Target, value); }
}
}
@@ -6,7 +6,7 @@ using System.Reflection;
namespace MonoGame.Extended.Tweening
{
public sealed class TweenPropertyMember<T> : TweenMember<T>
where T : struct
where T : struct
{
private readonly PropertyInfo _propertyInfo;
@@ -19,25 +19,29 @@ namespace MonoGame.Extended.Tweening
public override Type Type => _propertyInfo.PropertyType;
public override string Name => _propertyInfo.Name;
private static Func<object, object> CompileGetMethod(PropertyInfo propertyInfo)
//TODO: Try to further optimize this. For example, it needs to do all this reflection compilation shenanigan every time.
//Could we cache these instead?
private static Func<object, T> CompileGetMethod(PropertyInfo propertyInfo)
{
var param = Expression.Parameter(typeof(object));
var instance = Expression.Convert(param, propertyInfo.DeclaringType);
var convert = Expression.TypeAs(Expression.Property(instance, propertyInfo), typeof(object));
return Expression.Lambda<Func<object, object>>(convert, param).Compile();
var entityType = propertyInfo.DeclaringType!;
var parameter = Expression.Parameter(typeof(object), "entity");
var property = Expression.Property(Expression.Convert(parameter, entityType), propertyInfo);
return Expression.Lambda<Func<object, T>>(property, parameter).Compile();
}
private static Action<object, object> CompileSetMethod(PropertyInfo propertyInfo)
private static Action<object, T> CompileSetMethod(PropertyInfo propertyInfo)
{
Debug.Assert(propertyInfo.DeclaringType != null);
var param = Expression.Parameter(typeof(object));
var argument = Expression.Parameter(typeof(object));
var expression = Expression.Convert(param, propertyInfo.DeclaringType);
var methodInfo = propertyInfo.SetMethod;
var arguments = Expression.Convert(argument, propertyInfo.PropertyType);
var setterCall = Expression.Call(expression, methodInfo, arguments);
return Expression.Lambda<Action<object, object>>(setterCall, param, argument).Compile();
var entityType = propertyInfo.DeclaringType!;
var targetParam = Expression.Parameter(typeof(object), "target");
var valueParam = Expression.Parameter(typeof(T), "value");
var conversion = Expression.Convert(targetParam, entityType);
var methodInfo = propertyInfo.SetMethod!;
var set = Expression.Call(conversion, methodInfo, valueParam);
return Expression.Lambda<Action<object, T>>(set, targetParam, valueParam).Compile();
}
}
}
}