如何使用LINQ和C#更新包含列表的元素

13

我有一个对象列表,我想更新其中一个对象的特定成员变量。我知道LINQ是为查询而设计的,并不适用于更新不可变数据的列表。那么实现这个目标的最佳方式是什么?如果使用LINQ不是最有效的解决方案,我也不需要使用LINQ。

创建一个Update扩展方法是否可行?如果是,我该如何做到这一点?

EXAMPLE:
(from trade in CrudeBalancedList
 where trade.Date.Month == monthIndex
 select trade).Update(
 trade => trade.Buy += optionQty);

我看到了这篇文章,觉得链接到它对于任何想查找我的问题的人都是合适的。http://stackoverflow.com/questions/1344140/extension-method-for-update-in-linq-to-objects - Addie
4个回答

30

虽然 LINQ 不适用于更新不可变数据的列表,但它非常方便用于获取您想要更新的项目。 我认为对于您来说,这将是:

(from trade in CrudeBalancedList
    where trade.Date.Month == monthIndex
    select trade).ToList().ForEach( trade => trade.Buy += optionQty);

1
这将生成一个新的更新列表,还是更新CrudeBalancedList? - Nitin Sawant
2
在调用ToList()方法的时候,已经有一个符合条件的交易对象列表。由于没有变量引用这个列表,所以一旦执行完这行代码,它就会成为垃圾回收的目标。如果你想要利用这个列表来做更多的事情,而不仅仅是[trade.Buy += optionQty],那么你需要将这行代码拆分成几行。首先定义并设置一个变量,如下:List<trade> monthlyCrudeBalancedList = (from trade in etc. 然后下一行:monthlyCrudeBalancedList.ForEach(trade => etc. 然后,你就有了一个新列表的引用。 - Patrick Karcher

4
我不确定这是否是最好的方法,但它可以让您从列表中更新元素。
测试对象:
 public class SomeClass {
        public int Value { get; set; }
        public DateTime Date { get; set; }
    }

扩展方法:
public static class Extension {
        public static void Update<T>(this T item, Action<T> updateAction) {
            updateAction(item);
        }
    }

测试:

public void Test()
{
    // test data
    List<SomeClass> list = new List<SomeClass>()
    {
        new SomeClass {Value = 1, Date = DateTime.Now.AddDays(-1)},
        new SomeClass {Value = 2, Date = DateTime.Now },
        new SomeClass {Value = 3, Date = DateTime.Now.AddDays(1)}
    };
    // query and update
    (from i in list where i.Date.Day.Equals(DateTime.Now.Day) select i).First().Update(v => v.Value += 5);

    foreach (SomeClass s in list) {
        Console.WriteLine(s.Value);
    }
}

你可以这样写代码:(from i in list where i.Date.Day.Equals(DateTime.Now.Day) select i).First().Value+=4; - HellBaby

1

所以你期望在这里得到一个单一的结果。在这种情况下,你可以考虑使用 SingleOrDefault 方法:

var record =
    (from trade in CrudeBalancedList
    where trade.Date.Month == monthIndex
    select trade).SingleOrDefault();

if (record != null)
    record.Buy += optionQty;

请注意,SingleOrDefault 方法期望返回恰好一个或零个值(就像某些唯一主键的表中的一行)。如果返回多条记录,则该方法将引发异常。

或者使用类似的FirstOrDefault方法。如果返回多条记录,它不会抛出异常。 - WEFX

0
创建这样一个方法,您将从其原型开始:
public static class UpdateEx {
    public void Update(this IEnumerable<T> items, 
                       Expression<Action> updateAction) {
    }
}

这是容易的部分。

难点将是将 Expression<Action> 编译成 SQL 更新语句。根据您想要支持多少语法,这种编译器的复杂性可能从简单到不可能。

关于编译 Linq 表达式的示例,请参见 sqlite-net 项目TableQuery 类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接