在LINQ中更改动态类型的值?

时间:2011-03-03 08:02:54

标签: linq-to-entities aggregate dynamictype

我遇到LINQ问题。我有一个项目列表,我想用以下代码将孤儿项目的Parent值更改为0:

void Main()
{
    var a = new List<Item> {
        new Item() { ID = 1, Name = "1", Parent = 0 },
        new Item() { ID = 2, Name = "1.1", Parent = 1 },
        new Item() { ID = 3, Name = "2", Parent = 0 },
        new Item() { ID = 4, Name = "3", Parent = 0 },
        new Item() { ID = 5, Name = "1.2", Parent = 1 },
        new Item() { ID = 6, Name = "2.1", Parent = 3 },
        new Item() { ID = 7, Name = "2.2", Parent = 3 },
        new Item() { ID = 8, Name = "3.1", Parent = 4 },
        new Item() { ID = 9, Name = "4", Parent = 0 },
        new Item() { ID = 10, Name = "5.1", Parent = 11 }
    };

    Test.Fix(a, x => x.ID, x => x.Parent).Dump();
}

public class Item
{
    public long ID {get;set;}
    public string Name {get;set;}
    public long Parent {get;set;}
}

public static class Test
{
    public static List<T> Fix<T>(this List<T> enumeration, Func<T, long> idProperty, Func<T, long> parentProperty)
    {
        enumeration = enumeration.Select(e =>
        {
            if (!enumeration.Any(x => idProperty(x) == parentProperty(x))) parentProperty(e) = 0;
            return e;
        }).ToList();

        return enumeration;
    }
}

我希望ID = 10的持续项目有Parent = 0(因为ID = 11没有项目)但我收到错误:

The left-hand side of an assignment must be a variable, property or indexer

我用Google搜索,但仍然没有找到任何有用的信息。

任何帮助都将不胜感激!

1 个答案:

答案 0 :(得分:2)

好的,首先这里没有动态,但正如你所说,问题在于:

parentProperty(e) = 0;

parentProperty是一个函数,就是这样。它不是真正的属性。它允许您从Tlong - 这就是全部。它可以是任何东西 - 假设Func<string, long>返回x.Length * 5。 “设置”到(比如说)3?

是什么意思

如果您希望设置一个值,则需要一个操作,例如

public static List<T> Fix<T>(this List<T> enumeration,
                             Func<T, long> idProperty,
                             Func<T, long> parentGetter,
                             Action<T, long> parentSetter)
{
    enumeration = enumeration.Select(e =>
    {
        long parentId = parentGetter(e);
        if (!enumeration.Any(x => idProperty(x) == parentId))
        {
            parentSetter(e, 0);
        }
        return e;
    }).ToList();

    return enumeration;
}

并将其称为:

Test.Fix(a, x => x.ID, x => x.Parent, (x, v) => x.Parent = v).Dump();

请注意,我已经更改了Any中的逻辑,因为您当前的逻辑没有意义 - 它在测试中没有使用e

然而,这实际上并不是LINQ的好用 - LINQ是围绕没有副作用而设计的。鉴于您只返回与以前相同的元素,您可能不会返回任何内容,只需使用foreach循环:

public static void Fix<T>(this List<T> enumeration,
                             Func<T, long> idProperty,
                             Func<T, long> parentGetter,
                             Action<T, long> parentSetter)
{
    foreach (T item in enumeration)
    {
        long parentId = parentGetter(e);
        if (!enumeration.Any(x => idProperty(x) == parentId))
        {
            parentSetter(e, 0);
        }
    }
}

我个人然后将其更改为:

public static void Fix<T>(this List<T> enumeration,
                             Func<T, long> idProperty,
                             Func<T, long> parentGetter,
                             Action<T, long> parentSetter)
{
    HashSet<long> validIds = new HashSet<long>(enumeration.Select(idProperty));        
    foreach (T item in enumeration.Where(x => !validIds.Contains(parentGetter(x)))
    {
        parentSetter(e, 0);
    }
}