2017-05-05 147 views
5

我正在使用Unity。我使用IEnumerable.Select()来获取类型列表,并将它们(作为组件)添加到GameObject中。 运行此:C#LINQ Select()调用函数两次

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

实际上增加了相同类型的组分与游戏对象在问题的,虽然只newObjects包含于一个的引用。另一个创建的组件只是浮动,而不返回引用。 运行此:

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

Works和只会增加每种组件类型的游戏对象中的一个。但是,它看起来有点丑。 (IGameManager是一个接口,所有类型的问题实现。)

我可以只使用foreach循环,但这不完全雄辩,此外,我找不到任何文章在线解释此行为,因此我的好奇心越来越好了。

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

谢谢!

+2

types.Select(T =>(IGameManager)gameObject.AddComponent(t))的ToList() – loneshark99

+2

'Select()'不会调用提供的委托。它只构造延迟执行的'IEnumerable'对象。每次枚举结果的IEnumerable对象时都会调用委托。 – PetSerAl

回答

8

你没有提供你使用它的地方代码,你给的代码实际上并没有做任何事情,没有评估,只是设置了一个表达式树。

以某调戏你的代码,假设你可以得到的组件在游戏对象

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(); 
+0

这正是我上面的评论。 – loneshark99

+1

@ loneshark99是的,就这样。但这只是最后一行,问题本身是问“为什么” –

+0

明白了@KeithNicholas – loneshark99