如何使用LINQ优化Unity UI下拉框的数据填充代码以提升可读性
Great question! LINQ is perfect for simplifying this kind of nested loop logic and making your code more readable by focusing on what you want to do rather than how to loop through everything. Let's refactor your original code step by step.
Original Code Recap
Your current code loops through every entry in the TeamValuePair dictionary, checks if the key matches the selected team name, then loops through the associated list to add options to the dropdown. While it works, the nested loops can be hard to scan at a glance.
LINQ Refactor
Here's a cleaner, more declarative version using LINQ:
// Get the currently selected team name from the dropdown var selectedTeamName = teamNames.options[teamNames.value].text; // Use LINQ to filter, transform, and collect the dropdown options var screenOptions = TeamValuePair // Filter the dictionary to only the entry matching the selected team .Where(kvp => kvp.Key == selectedTeamName) // Flatten the list of NameIdValuePair objects from the matching entry .SelectMany(kvp => kvp.Value) // Convert each NameIdValuePair to a dropdown OptionData .Select(rec => new TMP_Dropdown.OptionData(rec.ScreenName)) // Materialize the result into a list for efficiency .ToList(); // Add all options to the dropdown in one go (more efficient than adding one by one) screenNamesDropDown.options.AddRange(screenOptions);
Breakdown of the LINQ Operations
Where: Filters the dictionary to keep only the key-value pair where the key matches the selected team name. This replaces your outer loop and conditional check.SelectMany: Takes the list ofNameIdValuePairfrom the matching dictionary entry and flattens it into a single sequence of objects (no more inner loop needed).Select: Converts eachNameIdValuePairinto aTMP_Dropdown.OptionDataobject using itsScreenNameproperty.ToList: Converts the LINQ query result into a list, which lets us useAddRangeinstead of adding options one by one (this is more efficient, especially for larger lists).
Even More Concise Version (Optional)
If you prefer a more compact approach (while still keeping readability), you can combine some steps using FirstOrDefault to directly get the matching dictionary entry:
var selectedTeamName = teamNames.options[teamNames.value].text; screenNamesDropDown.options.AddRange( TeamValuePair .FirstOrDefault(kvp => kvp.Key == selectedTeamName)? .Value .Select(rec => new TMP_Dropdown.OptionData(rec.ScreenName)) // Fallback to an empty collection if no matching team is found ?? Enumerable.Empty<TMP_Dropdown.OptionData>() );
The ? null-conditional operator ensures we don't get a null reference exception if the selected team name isn't present in the dictionary, and the ?? operator provides an empty collection as a fallback (just like your original code does nothing in that case).
A Quick Note for Unity
If you want to replace existing dropdown options instead of adding to them, don't forget to call screenNamesDropDown.ClearOptions(); before adding the new options.
内容的提问来源于stack exchange,提问作者Arjun

