UnityEditor GenericMenu - Problem with 'AddItem' in Foreach Loop
I'm working on a custom inspector and I'm trying to populate a GenericMenu with the content of a string array like this:
public override void OnInspectorGUI()
{
if(GUILayout.Button("Add Type"))
{
var menu = new GenericMenu();
foreach(string s in typeNames)
{
menu.AddItem(new GUIContent(s), false, () => Debug.Log("s = " + s));
}
menu.ShowAsContext();
Event.current.Use();
}
}
which works perfectly fine. The menu gets populated with all the different strings.
The problem is that, no matter what option I click on the generic menu later on, the Debug.Log() always prints the first element from the array. Can someone explain to me, why GUIContent(s) works, but the lambda expression doesn't?
Answer by stektpotet · Aug 04, 2018 at 01:13 PM
I'm not sure how capturing of variables work in C# lambdas, but I think that's the problem here... The state of the string isn't captured for the lambda, making them all print the same string.
A fix for this is to use the alternative GenericMenu.Menufunction2: Its signature is void(object)
and the correlated AddItem
-function takes an extra parameter which is the object that should be passed through the expression. For the case above:
menu.AddItem(new GUIContent(s), false, str => Debug.Log("s = " + (string)str), s);
The only difference between the two is the fact that the parameter s
now will be captured as part of the menu item allowing the item to pass the parameter through the lambda.
My best guess is that the compiler otherwise sees the lambda expression as the same expression for all the added menuitems, and therefore doesn't need to evaluate the value of s
before the loop is completed (though don't quote me on that, I'm pretty sure there's a better explanation of what's happening behind the scenes here).
Your answer
Follow this Question
Related Questions
AddListener in foreach 2 Answers
how to make a button make an image show inside another button 1 Answer
Cursor dissapearing in my menu 0 Answers
ReEnable mouse(movement,selection,etc) after loading game menu 1 Answer
Restart a Scene 1 Answer