2017-05-05 31 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