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()。等等,我喜欢这个。。。它的使用语法简洁明了。但是,它不允许对枚举中的每个元素执行具有副作用的任意泛型操作。。。您必须为要执行的每个新操作(您还没有扩展…)创建一个扩展方法。正如我所说,这是如果你真的想拥抱方法链接,而不是把它作为一种一次性的事情。我想你会有其他的课程来做举重,