Изменить значение динамического типа в LINQ? - PullRequest
0 голосов
/ 03 марта 2011

У меня проблема с 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

Я погуглил, но все еще не нашел ничего полезного.

Любая помощь будет оценена!

1 Ответ

2 голосов
/ 03 марта 2011

Хорошо, во-первых, здесь не происходит ничего динамического, но, как вы говорите, проблема здесь:

parentProperty(e) = 0;

parentProperty - это функция, вот и все. Это не действительно собственность. Это позволяет вам получить от T до long - и все. Это может быть что угодно - представьте 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...