5

I'm working on Unity and trying hard to make a custom SelectableButton that stores method(s) in two different delegates, and executes one whenever the button is selected and the other when it is deselected. The relevant part shows like that :

public delegate void OnSelectAction();
public delegate void OnDeselectAction();

public class SelectableButton : MonoBehaviour
{
    private bool selected;

    public OnSelectAction onSelect;
    public OnDeselectAction onDeselect;

    public bool Selected
    {
        get { return selected; }
        set
        {
            selected = value;

            if(selected)
                onSelect();
            else
                onDeselect();
        }
    }
}

On another script, I try to encapsulate a method in onSelect and another in onDeselect.

for(int i = 0; i < racesData.RaceList.Count; i++)
{
    selectableButton.onSelect = Select(racesData.RaceList[i]);
    selectableButton.onDeselect = Deselect(racesData.RaceList[i]);
}

public void Select(Race race)
{
// Does its selection stuff
}

public void Deselect(Race race)
{
// Does its deselection stuff
}

In the end, I end up with an error telling me that I can't "convert void to OnSelectAction/OnDeselectAction". And if I try to write it rather this way :

selectableButton.onSelect = () => Select(racesData.RaceList[i]);
selectableButton.onDeselect = () => Deselect(racesData.RaceList[i]);

The Select() and Deselect() methods don't execute the way they are supposed to. If someone could help in giving me the part that I'm lacking to make this work, it would be nice and I'd be grateful for the hand :)

1 Answers1

2

Your first attempt doesn't work because that's not how you assign delegates.

You need to do it like this:

selectableButton.onDeselect = Deselect;

Because you're assigning a method reference not the return value of a method call.

But because your Select/Deselect methods take a parameter, they don't match your delegate definitions. So you can't do it this way anyway (or you have to change the definition of your delegates to accept that parameter, but you probably don't want that).

So then we get to your lambda version, which assigns correctly, but doesn't function correctly. And it doesn't function correctly because of Function Closure.

for(int i = 0; i < racesData.RaceList.Count; i++)
{
    int j = i; //declare new local variable with a copy of the data
    selectableButton.onSelect = () => Select(racesData.RaceList[j]);
    selectableButton.onDeselect = () => Deselect(racesData.RaceList[j]);
}
  • This was so simple, this is so frustrating ! >< ^^" I didn't know about Function Closure, I'll take a look at that so I won't have any problem with this for the future. Thank you Draco ! :) – McGregor777 Dec 11 '19 at 17:08