public static class UpdateExtensions {
public delegate void Func<TArg0>(TArg0 element);
/// <summary>
/// Executes an Update statement block on all elements in an IEnumerable<T> sequence.
/// </summary>
/// <typeparam name="TSource">The source element type.</typeparam>
/// <param name="source">The source sequence.</param>
/// <param name="update">The update statement to execute for each element.</param>
/// <returns>The numer of records affected.</returns>
public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> update)
{
if (source == null) throw new ArgumentNullException("source");
if (update == null) throw new ArgumentNullException("update");
if (typeof(TSource).IsValueType)
throw new NotSupportedException("value type elements are not supported by update.");
int count = 0;
foreach (TSource element in source)
{
update(element);
count++;
}
return count;
}
}
int count = drawingObjects
.Where(d => d.IsSelected && d.Color == Colors.Blue)
.Update(e => { e.Color = Color.Red; e.Selected = false; } );
namespace System.Linq
{
/// <summary>
/// Class to hold extension methods to Linq.
/// </summary>
public static class LinqExtensions
{
/// <summary>
/// Changes all elements of IEnumerable by the change function
/// </summary>
/// <param name="enumerable">The enumerable where you want to change stuff</param>
/// <param name="change">The way you want to change the stuff</param>
/// <returns>An IEnumerable with all changes applied</returns>
public static IEnumerable<T> Change<T>(this IEnumerable<T> enumerable, Func<T, T> change )
{
ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
ArgumentCheck.IsNullorWhiteSpace(change, "change");
foreach (var item in enumerable)
{
yield return change(item);
}
}
/// <summary>
/// Changes all elements of IEnumerable by the change function, that fullfill the where function
/// </summary>
/// <param name="enumerable">The enumerable where you want to change stuff</param>
/// <param name="change">The way you want to change the stuff</param>
/// <param name="where">The function to check where changes should be made</param>
/// <returns>
/// An IEnumerable with all changes applied
/// </returns>
public static IEnumerable<T> ChangeWhere<T>(this IEnumerable<T> enumerable,
Func<T, T> change,
Func<T, bool> @where)
{
ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
ArgumentCheck.IsNullorWhiteSpace(change, "change");
ArgumentCheck.IsNullorWhiteSpace(@where, "where");
foreach (var item in enumerable)
{
if (@where(item))
{
yield return change(item);
}
else
{
yield return item;
}
}
}
/// <summary>
/// Changes all elements of IEnumerable by the change function that do not fullfill the except function
/// </summary>
/// <param name="enumerable">The enumerable where you want to change stuff</param>
/// <param name="change">The way you want to change the stuff</param>
/// <param name="where">The function to check where changes should not be made</param>
/// <returns>
/// An IEnumerable with all changes applied
/// </returns>
public static IEnumerable<T> ChangeExcept<T>(this IEnumerable<T> enumerable,
Func<T, T> change,
Func<T, bool> @where)
{
ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
ArgumentCheck.IsNullorWhiteSpace(change, "change");
ArgumentCheck.IsNullorWhiteSpace(@where, "where");
foreach (var item in enumerable)
{
if (!@where(item))
{
yield return change(item);
}
else
{
yield return item;
}
}
}
/// <summary>
/// Update all elements of IEnumerable by the update function (only works with reference types)
/// </summary>
/// <param name="enumerable">The enumerable where you want to change stuff</param>
/// <param name="update">The way you want to change the stuff</param>
/// <returns>
/// The same enumerable you passed in
/// </returns>
public static IEnumerable<T> Update<T>(this IEnumerable<T> enumerable,
Action<T> update) where T : class
{
ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
ArgumentCheck.IsNullorWhiteSpace(update, "update");
foreach (var item in enumerable)
{
update(item);
}
return enumerable;
}
/// <summary>
/// Update all elements of IEnumerable by the update function (only works with reference types)
/// where the where function returns true
/// </summary>
/// <param name="enumerable">The enumerable where you want to change stuff</param>
/// <param name="update">The way you want to change the stuff</param>
/// <param name="where">The function to check where updates should be made</param>
/// <returns>
/// The same enumerable you passed in
/// </returns>
public static IEnumerable<T> UpdateWhere<T>(this IEnumerable<T> enumerable,
Action<T> update, Func<T, bool> where) where T : class
{
ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
ArgumentCheck.IsNullorWhiteSpace(update, "update");
foreach (var item in enumerable)
{
if (where(item))
{
update(item);
}
}
return enumerable;
}
/// <summary>
/// Update all elements of IEnumerable by the update function (only works with reference types)
/// Except the elements from the where function
/// </summary>
/// <param name="enumerable">The enumerable where you want to change stuff</param>
/// <param name="update">The way you want to change the stuff</param>
/// <param name="where">The function to check where changes should not be made</param>
/// <returns>
/// The same enumerable you passed in
/// </returns>
public static IEnumerable<T> UpdateExcept<T>(this IEnumerable<T> enumerable,
Action<T> update, Func<T, bool> where) where T : class
{
ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
ArgumentCheck.IsNullorWhiteSpace(update, "update");
foreach (var item in enumerable)
{
if (!where(item))
{
update(item);
}
}
return enumerable;
}
}
}
我这样使用它:
List<int> exampleList = new List<int>()
{
1, 2 , 3
};
//2 , 3 , 4
var updated1 = exampleList.Change(x => x + 1);
//10, 2, 3
var updated2 = exampleList
.ChangeWhere( changeItem => changeItem * 10, // change you want to make
conditionItem => conditionItem < 2); // where you want to make the change
//1, 0, 0
var updated3 = exampleList
.ChangeExcept(changeItem => 0, //Change elements to 0
conditionItem => conditionItem == 1); //everywhere but where element is 1
参考参数检查:
/// <summary>
/// Class for doing argument checks
/// </summary>
public static class ArgumentCheck
{
/// <summary>
/// Checks if a value is string or any other object if it is string
/// it checks for nullorwhitespace otherwhise it checks for null only
/// </summary>
/// <typeparam name="T">Type of the item you want to check</typeparam>
/// <param name="item">The item you want to check</param>
/// <param name="nameOfTheArgument">Name of the argument</param>
public static void IsNullorWhiteSpace<T>(T item, string nameOfTheArgument = "")
{
Type type = typeof(T);
if (type == typeof(string) ||
type == typeof(String))
{
if (string.IsNullOrWhiteSpace(item as string))
{
throw new ArgumentException(nameOfTheArgument + " is null or Whitespace");
}
}
else
{
if (item == null)
{
throw new ArgumentException(nameOfTheArgument + " is null");
}
}
}
}
/// <summary>
/// Executes an Update statement block on all elements in an IEnumerable of T
/// sequence.
/// </summary>
/// <typeparam name="TSource">The source element type.</typeparam>
/// <param name="source">The source sequence.</param>
/// <param name="action">The action method to execute for each element.</param>
/// <returns>The number of records affected.</returns>
public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> action)
{
if (source == null) throw new ArgumentNullException("source");
if (action == null) throw new ArgumentNullException("action");
if (typeof (TSource).IsValueType)
throw new NotSupportedException("value type elements are not supported by update.");
var count = 0;
foreach (var element in source)
{
action(element);
count++;
}
return count;
}
void DoStuff()
{
Func<string, Foo, bool> test = (y, x) => { x.Bar = y; return true; };
List<Foo> mylist = new List<Foo>();
var v = from x in mylist
where test("value", x)
select x;
}
class Foo
{
string Bar { get; set; }
}
15 回答
虽然您可以使用
ForEach
扩展方法,但如果您只想使用框架,则可以执行此操作由于延迟评估,需要
ToList
才能立即评估选择 .我这样做
我实际上found an extension method会做我想要的
使用:
我不确定这是否过度使用LINQ,但是当想要更新列表中特定条件的特定项时,它对我有用 .
没有内置的扩展方法来执行此操作 . 虽然定义一个是相当直接的 . 在帖子的底部是我定义的一个名为Iterate的方法 . 它可以像这样使用
迭代源
我已经尝试了一些变化,我会继续回到这个人的解决方案 .
http://www.hookedonlinq.com/UpdateOperator.ashx
再次,这是别人的解决方案 . 但我已将代码编译成一个小型库,并定期使用它 .
我将在这里粘贴他的代码,因为他的网站(博客)在将来某个时候不再存在 . (没有什么比看到一篇帖子说“这是你需要的确切答案”,点击和死网更糟糕了 . )
不,LINQ不支持大规模更新方式 . 唯一更短的方法是使用
ForEach
扩展方法 - Why there is no ForEach extension method on IEnumerable?我的2便士: -
我写了一些扩展方法来帮助我解决这个问题 .
我这样使用它:
参考参数检查:
虽然你特意要求一个linq解决方案,但这个问题已经很久了,我发布了一个非linq解决方案 . 这是因为linq(= lanuguage integrated query )用于集合查询 . 所有linq方法都不会修改底层集合,它们只返回一个新集合(或更精确的迭代器到新集合) . 无论你做什么,例如使用
Select
不会影响基础集合,您只需获得一个新集合 .当然你可以使用
ForEach
(顺便说一句,这不是linq,而是List<T>
的扩展名) . 但是这个字面意思是使用foreach
但是使用lambda表达式 . 除此之外,每个linq方法都在内部迭代您的集合,例如通过使用foreach
或for
,它只是将其隐藏在客户端 . 我认为这不再具有可读性和可维护性(想想在调试包含lambda表达式的方法时编辑代码) .说完之后不要使用Linq来修改你馆藏中的物品 . 更好的方法是您在问题中提供的解决方案 . 使用经典循环,您可以轻松迭代您的收藏并更新其项目 . 事实上,依赖于
List.ForEach
的所有这些解决方案都没有什么不同,但从我的角度来看却难以理解 .因此,在您想要更新集合元素的情况下,不应该使用linq .
您可以使用LINQ将集合转换为数组,然后调用Array.ForEach():
显然,这不适用于结构集合或内置类型(如整数或字符串) .
这是我使用的扩展方法...
您可以使用Magiq,LINQ的批处理操作框架 .
我假设您要更改查询中的值,以便为其编写函数
但如果这就是你的意思,那不是舒尔 .