用Linq查询替换for-switch循环

Chr*_*ris 5 c# linq

我有一个Message对象,它包含了我无法控制的消息格式.格式是键/值对的简单列表.我想从给定的消息中提取用户列表.例如,给出以下消息......

1. 200->....
2. 300->....
3. ....
4. 405->.... 
5. 001->first_user_name
6. 002->first_user_phone
7. 003->first_user_fax
8. 001->second_user_name
9. 001->third_user_name
10. 002->third_user_phone
11. 003->third_user_fax
12. 004->third_user_address
13. .....
14. 001->last_user_name
15. 003->last_user_fax  
Run Code Online (Sandbox Code Playgroud)

我想用提供的属性集提取四个用户.初始键200/300 .... 405表示我不需要的字段,可以跳过以获取用户数据.

每个用户数据都在连续的字段中,但字段的数量取决于有关用户的信息量.以下方法可以满足我的需求.它使用可能的键类型的枚举和方法来查找具有用户数据的第一个字段的索引.

private List<User> ParseUsers( Message message )
{
    List<User> users = new List<User>( );
    User user = null; String val = String.Empty;

    for( Int32 i = message.IndexOfFirst( Keys.Name ); i < message.Count; i++ ) 
    {
        val = message[ i ].Val;

        switch( message[ i ].Key )
        {
            case Keys.Name:
                user = new User( val );
                users.Add( user ); 
                break;
            case Keys.Phone:
                user.Phone = val;
                break;
            case Keys.Fax:
                user.Fax = val;
                break;
            case Keys.Address:
                user.Address = val;
                break;
            default:
                break;
        }
    }

    return users;
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否有可能用Linq查询替换该方法.我无法告诉Linq选择新用户并使用所有匹配的数据填充其字段,直到找到下一个用户条目的开头.

注意:相对密钥编号在实际消息格式中是随机的(不是1,2,3,4).

dtb*_*dtb 5

我没有看到将代码更改为LINQ查询的好处,但它绝对可能:

private List<User> ParseUsers(Message message)
{
    return Enumerable
        .Range(0, message.Count)
        .Select(i => message[i])
        .SkipWhile(x => x.Key != Keys.Name)
        .GroupAdjacent((g, x) => x.Key != Keys.Name)
        .Select(g => g.ToDictionary(x => x.Key, x => x.Val))
        .Select(d => new User(d[Keys.Name])
        {
            Phone   = d.ContainsKey(Keys.Phone)   ? d[Keys.Phone]   : null,
            Fax     = d.ContainsKey(Keys.Fax)     ? d[Keys.Fax]     : null,
            Address = d.ContainsKey(Keys.Address) ? d[Keys.Address] : null,
        })
        .ToList();
}
Run Code Online (Sandbox Code Playgroud)

运用

static IEnumerable<IEnumerable<T>> GroupAdjacent<T>(
    this IEnumerable<T> source, Func<IEnumerable<T>, T, bool> adjacent)
{
    var g = new List<T>();
    foreach (var x in source)
    {
        if (g.Count != 0 && !adjacent(g, x))
        {
            yield return g;
            g = new List<T>();
        }
        g.Add(x);
    }
    yield return g;
}
Run Code Online (Sandbox Code Playgroud)