I can not understand how to pass a generic delegate/Action for a callback in another script?
I want different instances of this script to have different subscriptions to different delegates, however passing in an Action does not work (commented out code), the subscribed method never receives a callback.
However, if I do it with a very sloppy id system, it works. Does anyone know why?
Multicast delegates and delegates in general are immutable objects. When you use the += operator you actually replace the old delegate with the new “combined” multicast delegate. However parameters of a method are passed by value. So you replace the delegate only inside your method. The one you passed in won’t be changed. You could use a ref parameter in which case you can actually change the value of the passed variable inside your method. Since you did not post the code as text in code tags we can not copy your code and show the changes. Keep in mind that ref parameters also need to use the ref keyword when calling the method.
public static event Action<Stats, Action<float>, Action<float>> OnPlayerAdded = delegate { };
public event Action< float> OnHealthPctChanged = delegate { };
public event Action< float> OnBurstPctChanged = delegate { };
public void Initalize(Soldier soldier, StartingStats initalStats, bool isPlayer)
{
///other stuff
///register ourselves to this classes static events to set up a health bar in UI
if (!isPlayer)
OnAIHealthAdded(this);
else
OnPlayerAdded(this, OnHealthPctChanged, OnBurstPctChanged);
}
public void CalculateBurst(float dmg)
{
//do stuff
float currentBurstPct = (float)_currentBurst / (float)CalculateModifier(Modifier.eStat.BURSTMAX);
OnBurstPctChanged?.Invoke(currentBurstPct);
I get errors if I try to add “ref” keyword to the static event OnPlayerAdded
“Unexpected token ref” for declaration, and or "Argument may not be passed with the “ref” keyword "
Likewise I can not make UI_AIHealthBarController SetUpPlayerMeters take in by ref, because then they do not match the static call OnPlayerAdded which cant add the keyword ref
So I am thinking this isnt working because you cant pass by ref a instanced action via a static event?
So I changed the workflow so the UI_AIHealthBarController is a singleton as opposed to listening for theStats class static events. Now the Stats Class just calls the controller when it needs to.
You cannot add ref to generics like that, but what you can do is create your own delegate instead of using Action. I think the syntax look more or less like so:
Exactly. Many do not realise that System.Action is just a predefined delegate type (or multiple types when we consider all the generic versions). The “ref” is not part of the type itself, so you can not use it in a generic type parameter since that has to represent a type. The ref keyword generally changes how the parameter is passed to the method. This can not be changed by just switching out the type (which is what generics do).
So you would have to create your own delegate type like
Of course you can create your own generic type that takes one parameter passed by value and 2 parameters passed by reference. However since there are many combinations possible it would be a mess if you want to cover all cases.
For example:
public delegate void ActionVRR<T1,T2,T3> (T1, ref T2, ref T3);
So the “VRR” would indicate the first parameter is passed by value as usual and the second and third is passed by reference. Now you can use this generic delegate in place of your original Action delegate.
Note that a delegate with ref parameters are generally invariant (so no co- / contravariance). Though that’s pretty irrelevant for your case.
I have the feeling that you use too many delegates here. Having a method that subscribes a method to a passed in event and you call that method through another event seems like a quite tangled event mess. Though we don’t have the full picture. I just want to add that you should avoid subscribing / unsubscribing to C# events often as it has quite a bit of overhead. It completely duplicates all target delegates and creates a new multicast delegate whenever you add or remove a listener. Delegate types are immutable types in C# to avoid race conditions and sort of make them thread safe (at least the delegate / event variable itself). So adding a new listener will create a completely new delegate which is then stored in the variable. Keep in mind that C# does not have a seperate “+=” operator like C++. A += B is just a short hand for A = A + B. When used on delegates the + operator will just call Delegate.Combine with the two operands. It returns a new delegate which you assign back to the variable A.