I am trying to create a function that can linearly interpolate between two objects without knowing the implementation details of the containing class. Specifically, I want to apply this to Unity's ScriptableObject class to be able to interpolate between game data presets, but the question and concepts should apply to any C# object.
Here's what I have so far: I fetch the fields and properties of the class like this (Settable is just a wrapper around FieldInfo and PropertyInfo):
public static void LerpBetweenObjects<T>(T destinationObj, T startObj, T endObj, float t)
{
var type = typeof(T);
var props = type.GetProperties(bindingFlags);
var fields = type.GetFields(bindingFlags);
foreach (var item in props)
{
PropertyInfo itemLocal = item;
LerpBetweenMembersRefResult(new Settable(itemLocal), destinationObj, item.GetValue(startObj), item.GetValue(endObj), t);
}
foreach (var item in fields)
{
FieldInfo itemLocal = item;
LerpBetweenMembersRefResult(new Settable(itemLocal), destinationObj, item.GetValue(startObj), item.GetValue(endObj), t);
}
For the lerp function, my first thought was to just create a big switch statement, like this
public static void LerpBetweenMembersRefResult(ISettable result, object resultObj, object start, object end, float t)
{
switch (start)
{
case float floatStart:
result.SetValue(resultObj, Mathf.Lerp(floatStart, (float)end, t));
break;
case Color colorStart:
result.SetValue(resultObj, Color.Lerp(colorStart, (Color)end, t));
break;
default:
result = start;
break;
}
}
But then from reading some other answers on StackOverflow, people suggested using a function dictionary. So my version 2 looks like this:
private static Dictionary<Type, Action<ISettable, object, object, object, float>> lerpFuncsv2 = new Dictionary<Type, Action<ISettable, object, object, object, float>>()
{
{ typeof(float), (resultField, resObj, start, end, t) => resultField.SetValue(resObj, Mathf.Lerp((float)start, (float)end, t)) },
{ typeof(Color), (resultField, resObj, start, end, t) => resultField.SetValue(resObj, Color.Lerp((Color)start, (Color)end, t)) }
};
public static void LerpBetweenMembersRefResult(ISettable result, object resultObj, object start, object end, float t)
{
if (lerpFuncsv2.TryGetValue(start.GetType(), out Action<ISettable, object, object, object, float> action))
{
action?.Invoke(result, resultObj, start, end, t);
}
}
Version 2 looks more elegant, but it's about the same amount of typing, and comes with the downside of the invoke performance penalty. I'm wondering:
- Is there a method that's better than both of these?
- If not, then what is the benefit of using a function dictionary over a switch statement?
Aucun commentaire:
Enregistrer un commentaire