C# .Net可枚举扩展,它执行操作并返回相同的枚举
是否有方法使用C# .Net可枚举扩展,它执行操作并返回相同的枚举,c#,.net,linq,extension-methods,ienumerable,C#,.net,Linq,Extension Methods,Ienumerable,是否有方法使用IEnumerable扩展名(或任何其他IEnumerable扩展名) 执行与返回枚举的ForEach()等效的操作?i、 例如,您是否已经可以使用内置的IEnumerable扩展来实现此自定义扩展的等效功能 public static class EnumerableExtensions { public static IEnumerable<T> Do<T> (this IEnumerable<T> s
IEnumerable
扩展名(或任何其他IEnumerable
扩展名)
执行与返回枚举的ForEach()
等效的操作?i、 例如,您是否已经可以使用内置的IEnumerable
扩展来实现此自定义扩展的等效功能
public static class EnumerableExtensions
{
public static IEnumerable<T> Do<T>
(this IEnumerable<T> source, Action<T> action)
{
foreach (var elem in source)
{
action(elem);
yield return elem;
}
}
}
与您的方法等效的方法只是使用Select:
var x = list.Select(x => { x.Something(); return x; });
与您的方法等效的方法只是使用Select:
var x = list.Select(x => { x.Something(); return x; });
您可以使用:
var result = source.Select(x => { action(x); return x; });
当然,延迟评估意味着在评估结果之前,它不会被执行:
var result = source.Select(x => { action(x); return x; });
var list = result.ToList(); // action executed here for each element
如果枚举未完全枚举,则不会对所有元素调用操作:
var result = source.Select(x => { action(x); return x; });
var first = result.First(); // action executed here only for first element
如果用户多次枚举,您的操作将被多次枚举,如下面的人为示例所示:
var result = source.Select(x => { action(x); return x; });
if (result.Count() > 0) // Count() enumerates and calls action() for each element
{
return result.ToList(); // ToList() enumerates and calls action() again for each element.
}
else
{
return null;
}
依我看,依靠枚举的用户来确保操作只被调用一次可能会让人困惑,因此我通常会避免这种设计。您可以使用:
var result = source.Select(x => { action(x); return x; });
当然,延迟评估意味着在评估结果之前,它不会被执行:
var result = source.Select(x => { action(x); return x; });
var list = result.ToList(); // action executed here for each element
如果枚举未完全枚举,则不会对所有元素调用操作:
var result = source.Select(x => { action(x); return x; });
var first = result.First(); // action executed here only for first element
如果用户多次枚举,您的操作将被多次枚举,如下面的人为示例所示:
var result = source.Select(x => { action(x); return x; });
if (result.Count() > 0) // Count() enumerates and calls action() for each element
{
return result.ToList(); // ToList() enumerates and calls action() again for each element.
}
else
{
return null;
}
依靠枚举的用户来确保只调用一次操作可能会让人困惑,因此我通常会避免这种设计。您可以在几种LINQ扩展方法中引入副作用,如
Where
和Select
:
var en = enumeration.Where(x => { action(x); return true; });
或:
如果您的操作返回调用该操作时使用的值,则代码最短,然后您可以在扩展方法中将该方法用作委托:
var en = enumeration.Select(action);
或者如果它总是返回true
:
var en = enumeration.Where(action);
要实际调用该方法,还必须使用实际枚举集合的方法,如Last()
方法:
en.Last();
您可以在几种LINQ扩展方法中加入副作用,如
Where
和Select
:
var en = enumeration.Where(x => { action(x); return true; });
或:
如果您的操作返回调用该操作时使用的值,则代码最短,然后您可以在扩展方法中将该方法用作委托:
var en = enumeration.Select(action);
或者如果它总是返回true
:
var en = enumeration.Where(action);
要实际调用该方法,还必须使用实际枚举集合的方法,如Last()
方法:
en.Last();
微软发布了NuGet软件包,其中包括各种有用的扩展,如
Do()
你的例子是:
var Invoices = GetUnProcessedInvoices();
Invoices.Where(i=>i.Date > someDate)
.Do(i=>SendEmail(i.Customer))
.Do(i=>ShipProduct(i.Customer, i.Product, i.Quamtity))
.Do(i=>Inventory.Adjust(i.Product, i.Quantity));
将开箱即用。微软发布了NuGet软件包,其中包括各种有用的扩展,如
Do()
你的例子是:
var Invoices = GetUnProcessedInvoices();
Invoices.Where(i=>i.Date > someDate)
.Do(i=>SendEmail(i.Customer))
.Do(i=>ShipProduct(i.Customer, i.Product, i.Quamtity))
.Do(i=>Inventory.Adjust(i.Product, i.Quantity));
将开箱即用。好吧,我将添加我的评论作为答案。我认为如果您希望代码库使用链接,那么代码库应该真正支持它。否则,每个开发人员可能会也可能不会以您想要的功能样式编写。所以,我会这样做:
public static class EnumerableExtensions {
public static IEnumerable<Invoice> SendEmail(this IEnumerable<Invoice> invoices) {
foreach (var invoice in invoices) {
SendEmail(invoice.Customer);
yield return invoice;
}
}
public static IEnumerable<Invoice> ShipProduct(this IEnumerable<Invoice> invoices) {
foreach (var invoice in invoices) {
ShipProduct(invoice.Customer, invoice.Product, invoice.Quantity);
yield return invoice;
}
}
public static IEnumerable<Invoice> AdjustInventory(this IEnumerable<Invoice> invoices) {
foreach (var invoice in invoices) {
AdjustInventory(invoice.Product, invoice.Quantity);
yield return invoice;
}
}
private static void SendEmail(object p) {
Console.WriteLine("Email!");
}
private static void AdjustInventory(object p1, object p2) {
Console.WriteLine("Adjust inventory!");
}
private static void ShipProduct(object p1, object p2, object p3) {
Console.WriteLine("Ship!");
}
}
当然,我不确定ToList()部分。如果您忘记调用它,那么什么也不会发生:)。我只是复制了您当前的扩展方法,但不使用yield可能更有意义,这样您就可以:
invoices.SendEmail().ShipProduct().AdjustInventory();
好吧,我将添加我的评论作为回答。我认为如果您希望代码库使用链接,那么代码库应该真正支持它。否则,每个开发人员可能会也可能不会以您想要的功能样式编写。所以,我会这样做:
public static class EnumerableExtensions {
public static IEnumerable<Invoice> SendEmail(this IEnumerable<Invoice> invoices) {
foreach (var invoice in invoices) {
SendEmail(invoice.Customer);
yield return invoice;
}
}
public static IEnumerable<Invoice> ShipProduct(this IEnumerable<Invoice> invoices) {
foreach (var invoice in invoices) {
ShipProduct(invoice.Customer, invoice.Product, invoice.Quantity);
yield return invoice;
}
}
public static IEnumerable<Invoice> AdjustInventory(this IEnumerable<Invoice> invoices) {
foreach (var invoice in invoices) {
AdjustInventory(invoice.Product, invoice.Quantity);
yield return invoice;
}
}
private static void SendEmail(object p) {
Console.WriteLine("Email!");
}
private static void AdjustInventory(object p1, object p2) {
Console.WriteLine("Adjust inventory!");
}
private static void ShipProduct(object p1, object p2, object p3) {
Console.WriteLine("Ship!");
}
}
当然,我不确定ToList()部分。如果您忘记调用它,那么什么也不会发生:)。我只是复制了您当前的扩展方法,但不使用yield可能更有意义,这样您就可以:
invoices.SendEmail().ShipProduct().AdjustInventory();
可能不会,因为
动作(elem)代码>散发出副作用的气味;如果有什么区别的话,它将是一个Func()
而不是一个操作
;然后您可以将它与Select()
一起使用。这与LINQ
的整个设计完全相反。只需使用一个foreach
循环。所有在编辑过程中没有调用的副作用都是副作用。@CharlesBretana,你从来没有回答过我的问题,但我之所以问这个问题,是因为如果你确实想做方法链接,然后我认为更好的方法可能是使用专门针对IEnumerable的可枚举扩展方法,而不是通用的Do方法。然后您的代码变得非常容易阅读:例如,。elements.SomeMethodWithASideEffect()。等。可能不是,如动作(elem)代码>散发出副作用的气味;如果有什么区别的话,它将是一个Func()
而不是一个操作
;然后您可以将它与Select()
一起使用。这与LINQ
的整个设计完全相反。只需使用一个foreach
循环。所有在编辑过程中没有调用的副作用都是副作用。@CharlesBretana,你从来没有回答过我的问题,但我之所以问这个问题,是因为如果你确实想做方法链接,然后我认为更好的方法可能是使用专门针对IEnumerable的可枚举扩展方法,而不是通用的Do方法。然后您的代码变得非常容易阅读:例如,。elements.SomeMethodWithASideEffect()。等等,我喜欢这个。。。它的使用语法简洁明了。但是,它不允许对枚举中的每个元素执行具有副作用的任意泛型操作。。。您必须为要执行的每个新操作(您还没有扩展…)创建一个扩展方法。正如我所说,这是如果你真的想拥抱方法链接,而不是把它作为一种一次性的事情。我想你会有其他的课程来做举重,