TweenPropertyMember.cs 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. using System;
  2. using System.Diagnostics;
  3. using System.Linq.Expressions;
  4. using System.Reflection;
  5. namespace MonoGame.Extended.Tweening
  6. {
  7. public sealed class TweenPropertyMember<T> : TweenMember<T>
  8. where T : struct
  9. {
  10. private readonly PropertyInfo _propertyInfo;
  11. public TweenPropertyMember(object target, PropertyInfo propertyInfo)
  12. : base(target, CompileGetMethod(propertyInfo), CompileSetMethod(propertyInfo))
  13. {
  14. _propertyInfo = propertyInfo;
  15. }
  16. public override Type Type => _propertyInfo.PropertyType;
  17. public override string Name => _propertyInfo.Name;
  18. //TODO: Try to further optimize this. For example, it needs to do all this reflection compilation shenanigan every time.
  19. //Could we cache these instead?
  20. private static Func<object, T> CompileGetMethod(PropertyInfo propertyInfo)
  21. {
  22. var entityType = propertyInfo.DeclaringType!;
  23. var parameter = Expression.Parameter(typeof(object), "entity");
  24. var property = Expression.Property(Expression.Convert(parameter, entityType), propertyInfo);
  25. return Expression.Lambda<Func<object, T>>(property, parameter).Compile();
  26. }
  27. private static Action<object, T> CompileSetMethod(PropertyInfo propertyInfo)
  28. {
  29. Debug.Assert(propertyInfo.DeclaringType != null);
  30. var entityType = propertyInfo.DeclaringType!;
  31. var targetParam = Expression.Parameter(typeof(object), "target");
  32. var valueParam = Expression.Parameter(typeof(T), "value");
  33. var conversion = Expression.Convert(targetParam, entityType);
  34. var methodInfo = propertyInfo.SetMethod!;
  35. var set = Expression.Call(conversion, methodInfo, valueParam);
  36. return Expression.Lambda<Action<object, T>>(set, targetParam, valueParam).Compile();
  37. }
  38. }
  39. }