更改 LINQ 中动态类型的值?

发布于 2024-10-20 05:24:48 字数 1587 浏览 7 评论 0原文

我在使用 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 搜索了一下,但仍然没有找到任何有用的东西。

任何帮助将不胜感激!

I have a problem with LINQ. I have a list of item and I want to change the Parent value of an orphan item to 0 with the following code:

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;
    }
}

I expected the lasted item with ID = 10 to have Parent = 0 (coz there is no item with ID = 11) but I got an error:

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

I googled around but still find nothing useful.

Any helps would be appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

溇涏 2024-10-27 05:24:48

好吧,首先这里没有发生任何动态的事情,但正如你所说,问题就在这里:

parentProperty(e) = 0;

parentProperty 是一个函数,仅此而已。它并不是真正的财产。它允许您从 T 变为 long - 仅此而已。它可以是任何东西 - 想象一个返回 x.Length * 5Func。将其“设置”为(例如)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 a中的逻辑位,因为您当前的逻辑没有意义 - 它在测试中没有使用 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);
        }
    }
}

我个人then将其更改为:

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);
    }
}

Okay, firstly there's nothing dynamic going on here, but as you say, the problem is here:

parentProperty(e) = 0;

parentProperty is a function, that's all. It's not really a property. It allows you to get from a T to a long - and that's all. It could be anything - imagine a Func<string, long> which returned x.Length * 5. What would it mean to "set" that to (say) 3?

If you want to be able to set a value, you'll need an action, e.g.

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;
}

and call it like this:

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

Note that I've changed the logic in Any a bit because your current logic made no sense - it wasn't using e in the test.

However, this is really not a good use of LINQ - LINQ is designed around not having side-effects. Given that you're only returning the same elements as before, you might as well not return anything, and just use a foreach loop:

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);
        }
    }
}

I would personally then change this to:

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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文