C# - LINQ Select()调用函数两次

时间:2017-05-05 03:14:10

标签: c# linq select unity3d

我使用Unity。我使用IEnumerable.Select()获取类型列表并将它们(作为组件)添加到GameObject。 运行这个:

var newObjects = types.Select(t => (IGameManager)gameObject.AddComponent(t));

实际上将相同类型组件的两个添加到相关游戏对象中,尽管newObjects仅包含对一个的引用。另一个创建的组件只是浮动,而不返回引用。 运行这个:

foreach(var t in types)
{
    newObjects.Add((IGameManager)gameObject.AddComponent(t));
}

Works,并且只向GameObject添加每种组件类型中的一种。但是,它看起来有点难看。 (IGameManager是所有类型的接口实现的接口。)

我可以使用foreach循环,但这不完全是雄辩的,而且,我无法在网上找到任何解释这种行为的文章,因此我的好奇心越来越好。

所以,我的问题是:为什么Select()每次输入调用指定的函数两次,但只返回结果数据的一个副本?我该如何修复/预防/补偿这种行为?

谢谢!

1 个答案:

答案 0 :(得分:10)

您还没有提供使用它的周围代码,您提供的行实际上并没有做任何事情,没有评估任何内容,只是设置了表达式树。

对您的代码采取一些自由,并假设您可以访问游戏对象上的组件

 var gameObject = new GameObject();
 var types = new List<string>() { "a", "b", "c" };
 var newObjects = types.Select(t => (IGameManager)gameObject.AddComponent(t));
// at this point, nothing has happened....
 Console.WriteLine(gameObject.Components.Count());  // 0
 Console.WriteLine(newObjects.Count());   // 3 - we trigger the selects
 Console.WriteLine(gameObject.Components.Count()); // 3
 Console.WriteLine(newObjects.Count()); // 3 - we trigger the selects again
 Console.WriteLine(gameObject.Components.Count());  // 6

使用您的代码,您已经创建了一个表达式树,每次使用它时,它都会触发其中的表达式。我猜这是发生在你身上的事。您可以在我的代码中看到,每次您要求计数时,您都会在游戏对象中获得更多对象。

为了避免这种情况,可以通过将其转换为如下所示的列表或数组来评估它: -

var newObjects = types.Select(t => (IGameManager)gameObject.AddComponent(t)).ToList();