Reputation: 66
Ive got a following coroutine in unity:
IEnumerator DoActionUponReachingRangeCoroutine(Range range, Delegate action, params object[] args)
{
yield return new WaitUntil(() => range.isPlayerInRange);
action.DynamicInvoke(args);
yield return null;
}
As you can see it can execute some action when range.IsPlayerInRange condition is met. I would like to do exactly the same thing but with providing my own condition every time I call this method, not with isPlayerInRange hard-coded. Do I just provide a delegate instead of range?
Upvotes: 0
Views: 83
Reputation: 55
Look up c# reflection to create a clone of your function if you want to write your function once, but replicate it separately.
Get method info
MethodInfo mInfo = typeof(Program).GetMethod("SlotClick"); // inside the loop!!
https://learn.microsoft.com/en-us/dotnet/api/system.reflection.methodinfo?view=net-8.0
Then make a generic method changing the params to a type or types as needed. The docs explain,
Substitutes the elements of an array of types for the type parameters of the current generic method definition, and returns a MethodInfo
Below you’ll see my example building UI buttons and switching on a type.
public class ShieldButton {
public string ButtonImg;
public void activateSheild() {
// ...
};
}
public class Button {
// this is the method we will get the method info of!
// we are going to change the method parameters in the for loop when cloning.
// then we will invoke the cloned method..
public void click<T>(T Type) {
switch (typeOf(Type)) {
case ShieldButton: { Type.activateShield() };
}
}
}
public class CreateMenu {
public void InitiateMenu()
{
for (int i = 0; i < inventorySize; i++)
{
MethodInfo mInfo = typeof(Button).GetMethod("click"); // Grab the class and method!
MethodInfo newInfo = mInfo.MakeGenericMethod(typeof(ShieldButton)); // make a clone of the method changing the parameter type to our ShieldButton Class!
ShieldButton shieldButton = new ShieldButton(); // Create a new version of the shield button class
newSlot.GetComponent<Button>().onClick.AddListener(newInfo.Invoke(null, shieldButton)); // Invoke the new methodInfo passing in the class to switch on!!!!
}
}
}
Upvotes: 0
Reputation: 1063864
WaitUntil
takes Func<bool>
, so you can simply pass that down:
IEnumerator DoActionUponCoroutine(Func<bool> predicate, Delegate action, params object[] args)
{
yield return new WaitUntil(predicate);
action.DynamicInvoke(args);
yield return null;
}
You might also prefer Action
for the callback, which is much more efficient than DynamicInvoke
:
IEnumerator DoActionUponCoroutine(Func<bool> predicate, Action action)
{
yield return new WaitUntil(predicate);
action();
yield return null;
}
There is also a way of using generic TState state
and an Action<TState>
callback to avoid capture contexts, but... that's a more advanced scenario.
Upvotes: 3