【问题标题】:How to "return" multiple times with for loop?如何使用 for 循环多次“返回”?
【发布时间】:2022-09-26 09:12:42
【问题描述】:

希望这篇文章能更清楚地说明我想要实现的目标。

客观的:我想在运行时从列表中生成 20 个苹果(带有附加按钮)。当苹果被点击时,它们将产生一个弹出窗口,其中包含与被点击的苹果有关的信息。

我目前在做什么:我正在使用 for 循环遍历列表以生成苹果。我目前有以下代码:

public class AppleInventory : MonoBehaviour
{
   [SerializeField] private ApplesScript applPrefab;
   [SerializeField] private Transform applParent;
   
    public ApplesScript CreateApples()
    {
        var appl = Instantiate(applPrefab, applParent);

        for (int i = 0; i < apples.Count; i++)
        {
            appl = Instantiate(applPrefab, applParent);
            appl.InitAppleVisualization(apples[i].GetAppleSprite());
            appl.AssignAppleButtonCallback(() => CreateApplePopUpInfo(i));
            appl.transform.position = new Vector2(apples[i].x, apples[i].y);
        }

        return appl;
    }
}

问题:问题是当我使用for循环并单击按钮时,它返回以下错误:ArgumentOutOfRangeException:索引超出范围。必须是非负数且小于集合的大小。弹出信息也不会更新。

没有for循环的代码:当我删除 for 循环并将 int i = 设置为特定数字时,该代码可以生成一个苹果,如下所示。它将为 \"i\" 设置的任何数字提供正确的弹出信息。这让我知道问题不是其余的代码。这使我相信这是问题所在的“返回”行以及 for 循环。似乎我可能需要为每次迭代“返回”,但我不确定如何去做。

public ApplesScript CreateApples()
{
   int i = 7;

   var appl = Instantiate(applPrefab, applParent);
   appl.InitAppleVisualization(apples[i].GetAppleSprite());
   appl.AssignAppleButtonCallback(() => CreateApplePopUpInfo(i));
   appl.transform.position = new Vector2(apples[i].x, apples[i].y);

   return appl;
}

谢谢,

-

更新修复非常简单。我刚刚为 for 循环创建了一个新方法,它按我想要的方式工作。我的代码现在看起来像这样:

public void StarterOfApplesCreation()
{
   for (int i = 0; i < apples.Count; i++)
   {
       CreateApples(i);
   }
}

public void CreateApples(int i)
{
   var appl = Instantiate(applPrefab, applParent);
   appl.InitAppleVisualization(apples[i].GetAppleSprite());
   appl.AssignAppleButtonCallback(() => CreateApplePopUpInfo(i));
   appl.transform.position = new Vector2(apples[i].x, apples[i].y);

}
  • 你为什么在循环之前打电话给Instantiate?当在循环内调用Instantiate 时,在那里创建的任何对象都会立即被替换,所以它是没有意义的。
  • 我只是把它放在那里,否则返回行中的“appl”会显示一个未定义的错误。
  • 但事实并非如此。如果你想在循环外使用它,你需要在循环外声明变量,但这并不意味着你也必须在那里调用Instantiate。不要创建你不需要的对象。声明变量和创建对象是两件不同的事情。

标签: c# unity3d


【解决方案1】:

你有两个选择。常规选项是首先创建所有项目,然后将它们全部返回到某种列表中,例如

public static void Main()
{
    foreach (var thing in GetThings(5))
    {
        Console.WriteLine(thing.Number);
    }

    Console.ReadLine();
}

public static Thing[] GetThings(int count)
{
    var things = new Thing[count];

    for (var i = 0; i < count; i++)
    {
        things[i] = new Thing { Number = i };
    }

    return things;
}

更现代的选择是使用iterator。它实际上一次返回一个项目。它的限制是你必须在那里使用这些项目 - 你不会像数组等那样随机访问 - 但它也有优势,例如

public static void Main()
{
    foreach (var thing in GetThings(5))
    {
        Console.WriteLine(thing.Number);
    }

    Console.ReadLine();
}

public static IEnumerable<Thing> GetThings(int count)
{
    for (var i = 0; i < count; i++)
    {
        var thing = new Thing { Number = i };

        yield return thing;
    }
}

迭代器的结果通常用作foreach 循环或LINQ 查询的源。请注意,如果您确实希望在特定情况下进行随机访问,则始终可以在迭代器的结果上调用 ToArrayToList,但在其他地方您仍然拥有迭代器的优势。例如,假设您的方法生成了 1000 个项目,并且您想找到第一个匹配某个条件的项目。使用我的第一个示例,您必须每次创建所有 1000 个项目,即使第一个是匹配项。使用迭代器,因为项目是在创建时处理的,所以您可以在找到匹配项后立即中止该过程,这意味着您不会不必要地创建剩余的项目。

请注意,我的示例使用以下类:

public class Thing
{
    public int Number { get; set; }
}

您可以将代码复制并粘贴到不使用顶级语句的控制台应用程序中。代码的骨架仍然适用于顶级语句,但您需要进行一些其他修改。

【讨论】:

    【解决方案2】:

    将实例化的每个单独的“appl”存储在一个数组中,即 appls[i]=appl

    在 for 循环中执行此操作。

    如果您考虑一下,请输入“return appl;”行在 for 循环之外,您只存储最后一个游戏对象,而不是全部。这就是为什么创建一个游戏对象数组并在循环中分配它们可能对您有用。

    【讨论】:

      猜你喜欢
      • 2013-10-13
      • 2019-05-01
      • 1970-01-01
      • 2021-09-28
      • 2021-12-20
      • 2019-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多