c#扩展方法,而不是迭代
本文关键字:迭代 扩展 方法 | 更新日期: 2023-09-27 18:07:57
我想知道,如果有一个扩展方法允许我迭代List,让我对列表中的每个项目做同样的事情。例如:
.RemoveAll(x => x.property == somevalue)
删除所有满足条件的元素。但是,如果我有这个呢:
foreach(object item in lstObjects)
{
object MyObject = new object();
MyObject.propertyone = item.property
MyObject.propertytwo = somevalue;
anotherlist.Add(MyObject);
}
当然,实际的代码要比这复杂一些。我的目标是,而不是foreach
使用扩展方法,我已经找到了List<T>.ForEach()
,但我不能让它工作,这个方法不存在于var列表中。我也发现了.Select<>
, .Where<>
,但这返回值,在我的方法中不需要返回任何值。
var convertedItems = lstObjects.Select(item =>
{
object MyObject = new object();
MyObject.propertyone = item.property
MyObject.propertytwo = somevalue;
return MyObject;
});
anotherList.AddRange(convertedItems);
或
anotherList = convertedItems.ToList();
,如果你想让它更短:
var convertedItems = lstObjects.Select(item =>
new object {propertyone = item.property, propertytwo = somevalue});
我不知道为什么要在这里使用扩展方法。List<T>.ForEach()
将完成您喜欢的大部分工作,但是现有的foreach
循环既习惯又可读。你为什么不能写一个普通的函数来做这个呢?
public void DoMyThing(IList<object> objects) {
foreach (var obj in objects) {
someOtherList.Add(new MyObj() {
item1 = obj
});
}
}
一般来说,如果您发现需要改变项而不返回值,则不希望使用LINQ或查询操作符。就用foreach
吧
Select()
将适用于这个简单的代码,但你的状态
实际代码要比
复杂一些
对我来说,这表明您可能必须在迭代期间改变一些其他状态。Select
方法将推迟这个突变,直到序列具体化;这可能会给你奇怪的结果,除非你熟悉LINQ查询如何延迟执行和捕获外部变量。
编写自己的ForEach扩展很简单。我在所有的代码中包含以下内容:
public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action )
{
foreach (T item in collection)
{
action(item);
}
}
您可以通过Select语句完成此操作:
var newList = lstObjects.Select(o =>
new { propertyone = o.property,
propertytwo = somevalue }).ToList();
下面是如何使用ForEach
和lambda表达式:
lstObjects.ForEach(item =>
{
MyObject obj = new MyObject();
obj.propertyone = item.property;
obj.propertytwo = somevalue;
anotherlist.Add(obj);
});
然而,正如你所看到的,它看起来与你已经拥有的非常相似!
另外,在我看来,Select
可能是你想要做的更好的匹配:
anotherList.AddRange(lstObjects.Select(item => new MyObject()
{
propertyone = item.property,
obj.propertytwo = somevalue,
}));
List<MyObjectType> list = new List<MyObjectType>();
list.ForEach((MyObjectType item) => {
object MyObject = new object()
{
MyObject.propertyone = item.property,
MyObject.propertytwo = somevalue
};
anotherlist.Add(MyObject);
});
如果你想要执行一个动作作为迭代的一部分,你可能想要考虑. do方法,它是交互式扩展的一部分。见http://www.thinqlinq.com/Post.aspx/Title/Ix-Interactive-Extensions-return。
您可以轻松地创建一个扩展方法来做到这一点:
public IEnumerable<T> RemoveAll(this List<T> list, Func<bool, T> condition)
{
var itemsToRemove = list.Where(s => condition(s));
list.RemoveAll(itemsToRemove);
}
你可以这样称呼它:
myList.RemoveAll(x => x.Property == someValue);
编辑:这里是另一个方法做同样的。
就'内置'而言,没有.ForEach()
;然而,我认为.Aggregate()
将是这里最合适的选择(如果你绝对完全想要一个内置函数)。
lstObjects.Aggregate(anotherList, (targetList, value) =>
{
object MyObject = new object();
MyObject.propertyone = item.property
MyObject.propertytwo = somevalue;
targetList.Add(MyObject);
return targetList;
});
你可以写你自己的扩展方法:
public static IEnumerable<T> Intercept<T>(this IEnumerable<T> values, Action<T> each)
{
foreach (var item in values)
{
each(item);
yield return item;
}
}
public static IEnumerable<T> Intercept<T>(this IEnumerable<T> values, Action<T, int> each)
{
var index = 0;
foreach (var item in values)
{
each(item, index++);
yield return item;
}
}
// ...
a.Intercept(x => { Console.WriteLine(x); }).Count();
注:我不像其他人那样创建ForEach的原因是微软没有包含它,因为按照设计,Linq方法总是返回一个值,或一个值列表。
特别针对你的问题,.Select<T>
可以解决这个问题。
anotherList.AddRange(lstObjects.Select(x => new MyObject()
{
propertyone = x.property,
propertytwo = somevalue
}));