I am creating a game in Unity3d
using the GREE c#
API.
I am trying to get run an Action
for every (username, score) in a leader board.
The code is the following:
public static void LoadBestScoreFromFriends(Action<FriendAndScore> onComplete)
{
Gree.Leaderboard.LoadScores(LEADERBOARD_ID,
UnityEngine.SocialPlatforms.UserScope.FriendsOnly,
UnityEngine.SocialPlatforms.TimeScope.AllTime,
1,
100,
(IScore[] scores) => {
foreach (IScore iscore in scores)
{
// Since the username is needed, a second
// call to the API must be done
Gree.User.LoadUser(iscore.userID,
(Gree.User guser) => {
FriendAndScore friend = new FriendAndScore();
friend.Name = guser.nickname;
friend.Score = "" + iscore.value;
// Run the action for every (nickname, score value)
onComplete(friend);
}, (string error) => {
Debug.Log("Couldn't fetch friend! error: " + error);
});
}
});
}
The problem here is that the iscore.value
it's always the same. It's the last element of the foreach
. This make sense because the LoadUser()
finishes after the foreach
ends its loop.
I thought of creating a second method to do the call there. Something like:
private void GetTheUserAndCallTheAction(Action<FriendAndScore> onComplete, string userID, string score)
{
Gree.User.LoadUser(userID,
(Gree.User guser) => {
FriendAndScore friend = new FriendAndScore();
friend.Name = guser.nickname;
friend.Score = score;
onComplete(friend);
}, (string error) => {
Debug.Log("Couldn't fetch friend! error: " + error);
});
}
Since I am a C#
newbie I wanted to know if there is a better way of handling this.
By design - this is how capture works when constructing lambda expression in foreach loop and executing this lambda later.
Fix - declare local copy of IScore iscore
:
foreach (IScore eachScore in scores)
{
IScore iscore = eachScore;
And Closing over the loop variable... by Eric Lippert details the behavior and related issues.