Linq延伸。更改源列表中的属性值

时间:2013-09-06 14:06:56

标签: c# linq extension-methods

我做了这个扩展,我必须修改源列表中属性的值。我遇到的问题是它不会更改源列表中的值,项目的值会更改。

这是我的扩展名:

public static IEnumerable<TSource> SetIndex<TSource, TResult>(
    this IEnumerable<TSource> source, 
    Expression<Func<TSource, TResult>> propertyExpression)
{
    MemberExpression body = propertyExpression.Body as MemberExpression;
    if (body == null)
    {
        return source;
    }

    PropertyInfo propertyInfo = body.Member as PropertyInfo;
    if (propertyInfo == null || propertyInfo.PropertyType != typeof(int))
    {
        return source;
    }

    string propertyName = body.Member.Name;
    int index = 0;
    foreach (TSource item in source)
    {
        propertyInfo.SetValue(item, index++, null);
    }

    return source;
}

这是我要测试的代码:

public class Persona
{
    public string Name { get; set; }

    public string Lastname { get; set; }
}

public class PersonaGroup
{
    public string Lastname { get; set; }

    public int Count { get; set; }

    public int Index { get; set; }
}


IList<Persona> listPersonas = new List<Persona>()
{
    new Persona{ Lastname = "Lopez", Name = "Tilo" },
    new Persona{ Lastname = "Dominguez", Name = "Raul" },
    new Persona{ Lastname = "Martinez", Name = "Manuel" },
    new Persona{ Lastname = "Martinez", Name = "Rogelio" },
    new Persona{ Lastname = "Lopez", Name = "Roberto" },
    new Persona{ Lastname = "Martinez", Name = "Alen" },
    new Persona{ Lastname = "Lopez", Name = "Mario" },
    new Persona{ Lastname = "Dominguez", Name = "Duran" },
    new Persona{ Lastname = "Martinez", Name = "Maria" },
    new Persona{ Lastname = "Dominguez", Name = "Marta" },
    new Persona{ Lastname = "Lopez", Name = "Pedro" },
    new Persona{ Lastname = "Dominguez", Name = "Martin" },
    new Persona{ Lastname = "Dominguez", Name = "Diego" },
    new Persona{ Lastname = "Lopez", Name = "El" }
};

IList<PersonaGroup> listPersonasGroups = listPersonas
                                .GroupBy(p => p.Lastname)
                                .Select(pg => new PersonaGroup { Lastname = pg.Key, Count = pg.Count() })
                                .SetIndex(pg => pg.Index)
                                .ToList();

foreach (PersonaGroup personaGroup in listPersonasGroups)
{
    Console.WriteLine("{0} - {1} : {2}", 
                personaGroup.Index, 
                personaGroup.Count, 
                personaGroup.Lastname);
}

Console.ReadKey();

结果:

0 - 5 : Lopez
0 - 5 : Dominguez
0 - 4 : Martinez

当我写了我的问题时,我发现问题是在使用Select时,但我不知道如何解决它或为什么我无法修改列表。 我知道我可以在yield return item;中使用foreach,但更改“来源”会更有用。

感谢。

2 个答案:

答案 0 :(得分:3)

您可以使用标准LINQ方法执行所需操作:

IList<PersonaGroup> listPersonasGroups = listPersonas
                                .GroupBy(p => p.Lastname)
                                .Select((pg, i) => new PersonaGroup {
                                                        Lastname = pg.Key,
                                                        Count = pg.Count(),
                                                        Index = i
                                })
                                .ToList();
带有Select参数的

Func<TSource, int, TResult>重载与您的自定义扩展方法类似:

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    if (selector == null)
    {
        throw Error.ArgumentNull("selector");
    }
    return Enumerable.SelectIterator<TSource, TResult>(source, selector);
}

private static IEnumerable<TResult> SelectIterator<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
    int num = -1;
    checked
    {
        foreach (TSource current in source)
        {
            num++;
            yield return selector(current, num);
        }
        yield break;
    }
}

答案 1 :(得分:1)

问题在于这段代码:

foreach (TSource item in source)
{
    propertyInfo.SetValue(item, index++, null);
}
return source;

source被推迟IEnumerable,你可以枚举两次。在return source;中根本没有变化。例如,您可以将其更改为:

var array = source.ToArray();
foreach (TSource item in array)
{
    propertyInfo.SetValue(item, index++, null);
}
return array;