我想知道当需要来自多个记录的单个值时,是否有一些聪明的方法可以使用LINQ从可枚举中检索数据。
例如,假设您有一个拥有三个不同电话字段的人:
public class Person
{
public Phone HomePhone { get; set; }
public Phone WorkPhone { get; set; }
public Phone CellPhone { get; set; }
}
...但电话列表以标准格式存储:
public enum PhoneType
{
Home, Work, Cell
}
public class Phone
{
public PhoneType Type { get; set; }
public string Number { get; set; }
}
static public IEnumerable<Phone> GetPhoneList()
{
yield return new Phone { Type = PhoneType.Home, Number = "8005551212" };
yield return new Phone { Type = PhoneType.Work, Number = "8005551313" };
yield return new Phone { Type = PhoneType.Cell, Number = "8005551414" };
}
如果你需要填充Person,你可以写一个循环,并在一遍中获得你需要的一切:
public static Person GetPerson1()
{
var result = new Person();
foreach (var ph in GetPhoneList())
{
switch (ph.Type)
{
case PhoneType.Home: result.HomePhone = ph; break;
case PhoneType.Work: result.WorkPhone = ph; break;
case PhoneType.Cell: result.CellPhone = ph; break;
}
}
return result;
}
但是如果你想使用LINQ,似乎可能需要三次传递:
public static Person GetPerson2()
{
return new Person
{
HomePhone = GetPhoneList().Single( ph => ph.Type == PhoneType.Home ),
WorkPhone = GetPhoneList().Single( ph => ph.Type == PhoneType.Work ),
CellPhone = GetPhoneList().Single( ph => ph.Type == PhoneType.Cell )
};
}
是否有一种聪明的方法可以使用LINQ通过枚举只传递一次来获取所有内容?
如果您想浏览我的代码,可以使用link to a Fiddle。
(我知道我可以使用字典或其他数据结构来解决这个特殊问题;这只是一个例子。)
答案 0 :(得分:4)
通常情况下,您无法在LINQ中执行此操作。
如果您真的想要,可以创建一个Foreach扩展方法,并执行与GetPerson1
方法相同的操作。
public static class Ext
{
public static void Foreach<T>(this IEnumerable<T> e, Action<T> action)
{
foreach (T item in e)
{
action(item);
}
}
}
然后
public static Person GetPerson2()
{
var p = new Person();
var pl = GetPhoneList();
pl.Foreach(ph =>
{
switch (ph.Type)
{
case PhoneType.Home: p.HomePhone = ph; break;
case PhoneType.Work: p.WorkPhone = ph; break;
case PhoneType.Cell: p.CellPhone = ph; break;
}
});
return p;
}
但你真的不应该这样做。 LINQ意味着在IEnumerables上运行(逐项),LINQ函数应该没有副作用,而foreach循环和Foreach扩展方法只是创建副作用,改变Person对象的状态。
而且,此外,你需要一个聪明的方式&#39;应该表明这不是它的意思:)
Eric Lippert撰写了一篇很棒的文章,详细信息如下:https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/
答案 1 :(得分:3)
如果无法保证来自同一个人的数字按顺序排列,那么您必须枚举该列表,直到找到所有数字。在我看来,这不是LINQ的理想选择,其目的是使代码更具可读性。你的foreach
很好,我会在找到所有数字时打破循环。
如果你想列举所有人,而不只是一个人,那么Dictionary
方法可能是最有效的。 GroupBy
在内部使用字典,您可以使用GroupBy
收集属于某个人的所有数字,然后Aggregate
从中Person
制作Phone.PersonID
。我们假设有一些属性Person.PersonID
,还有GetPhoneList()
.GroupBy(x => x.PersonID)
.Select(x => x.Aggregate(new Person() { PersonID = x.Key },
(person, phone) =>
{
switch (phone.Type)
{
case PhoneType.Home: person.HomePhone = phone; break;
case PhoneType.Work: person.WorkPhone = phone; break;
case PhoneType.Cell: person.CellPhone = phone; break;
}
return person;
}));
,那么你会有这样的东西:
GetPhoneList()
我在此假设<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
返回所有人的所有电话。