我编写了以下代码来设置各种类的属性.它有效,但我的新一年的解决方案之一是尽可能多地使用LINQ,显然这段代码没有.有没有办法以"纯LINQ"格式重写它,最好不使用foreach循环?(如果可以在单个LINQ语句中完成,则更好 - 子语句很好.)
我试过玩,join但这并没有把我带到任何地方,因此我要求回答这个问题 - 最好没有解释,因为我更喜欢"反编译"解决方案以弄清楚它是如何工作的.(正如你可能猜到的那样,我目前在阅读LINQ方面比写它更好,但我打算改变它...)
public void PopulateBlueprints(IEnumerable<Blueprint> blueprints)
{
XElement items = GetItems();
// item id => name mappings
var itemsDictionary = (
from item in items
select new
{
Id = Convert.ToUInt32(item.Attribute("id").Value),
Name = item.Attribute("name").Value,
}).Distinct().ToDictionary(pair => pair.Id, pair => pair.Name);
foreach (var blueprint in blueprints)
{
foreach (var material in blueprint.Input.Keys)
{
if (itemsDictionary.ContainsKey(material.Id))
{
material.Name = itemsDictionary[material.Id];
}
else
{
Console.WriteLine("m: " + material.Id);
}
}
if (itemsDictionary.ContainsKey(blueprint.Output.Id))
{
blueprint.Output.Name = itemsDictionary[blueprint.Output.Id];
}
else
{
Console.WriteLine("b: " + blueprint.Output.Id);
}
}
}
Run Code Online (Sandbox Code Playgroud)
必要类的定义如下; 它们只是数据的容器,我已经删除了与我的问题无关的所有内容:
public class Material
{
public uint Id { get; set; }
public string Name { get; set; }
}
public class Product
{
public uint Id { get; set; }
public string Name { get; set; }
}
public class Blueprint
{
public IDictionary<Material, uint> Input { get; set; }
public Product Output { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我不认为这实际上是转换为LINQ的好选择 - 至少目前的形式不是这样.
是的,你有一个嵌套的foreach循环 - 但是你在顶级foreach循环中做了其他的事情,所以它不是易于转换的形式,只包含嵌套.
更重要的是,代码的主体是关于副作用的,无论是写入控制台还是更改您找到的对象中的值.LINQ很棒,当你有一个复杂的查询,你想循环它依次对每个项目采取行动,可能有副作用......但你的查询并不是很复杂,所以你不会得到太多效益.
有一两件事你可以做的就是给Blueprint并Product包含一个通用的接口Id和Name.然后,您可以itemsDictionary根据每个查询编写一个方法来更新产品和蓝图:
UpdateNames(itemsDictionary, blueprints);
UpdateNames(itemsDictionary, blueprints.SelectMany(x => x.Input.Keys));
...
private static void UpdateNames<TSource>(Dictionary<string, string> idMap,
IEnumerable<TSource> source) where TSource : INameAndId
{
foreach (TSource item in source)
{
string name;
if (idMap.TryGetValue(item.Id, out name))
{
item.Name = name;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这假设您实际上不需要控制台输出.如果这样做,您可以始终传入适当的前缀并在方法中添加"else"块.请注意,我已经使用TryGetValue而不是在每次迭代的字典上执行两次查找.
| 归档时间: |
|
| 查看次数: |
3864 次 |
| 最近记录: |