2014-03-05 39 views
1

是否有使用IEnumerable扩展Select(或任何其他IEnumerable扩展) 执行ForEach()返回枚举相当于一种方式?即,您是否可以使用内置的扩展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; 
     } 
    } 
} 

对于下面的评论,这个方法与调用foreach不完全一样。在foreach的情况下,枚举不返回。在这种情况下,施工的目的只是为了执行这个动作,所以它很难被称为副作用。

它允许操作的链接,如

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)); 
+4

或许不会,因为'行动(ELEM);副作用'恶臭。 –

+0

确实;如果有的话,它将是一个'Func ()'而不是'Action';然后你可以用'Select()'来使用它。 –

+2

[LINQ设计者主动选择不包含这种方法。](http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx)这完全相反“LINQ”的整个设计。只需使用'foreach'循环。 – Servy

回答

2

微软发布了NuGet软件包Ix-Main,其中包括各种有用的扩展,如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)); 

将工作开箱。

0

你的方法是等效的只是使用选择:

var x = list.Select(x => { x.Something(); return x; }); 
4

你可以使用:

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; 
} 

恕我直言,它可能混淆依靠你的枚举的用户,以确保您的行动调用一次,所以我一般会避免这样的设计。

0

你可以把一个副作用几个LINQ扩展方法,如WhereSelect

var en = enumeration.Where(x => { action(x); return true; }); 

或:

var en = enumeration.Select(x => { action(x); return x; }); 

您可以用最短的代码,如果你的行动返回它的值被调用,那么您可以在扩展方法使用的方法为代表:

var en = enumeration.Select(action); 

,或者如果它总是返回true

var en = enumeration.Where(action); 

要使方法居然叫,你也可以选择使用的东西,实际上将枚举集合,如Last()方法:

en.Last(); 
0

好吧,我会添加我的评论作为答案。我认为如果你想让代码库使用链接,那么代码库应该真的支持它。否则,每个开发人员可能会或可能不会写入您想要的功能样式。所以,我这样做:

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!"); 
    } 
} 

那么你的代码变成:

invoices.SendEmail().ShipProduct().AdjustInventory().ToList(); 

当然,我不知道的ToList()的一部分。如果你忘记打电话,那么没有任何反应:)。我只是复制当前的扩展方法,但它可能会更有意义,不使用屈服,让你可以只是做:

invoices.SendEmail().ShipProduct().AdjustInventory(); 
+0

我喜欢这个......它的使用语法简洁明了。但是,它并不允许在枚举中的每个元素上执行具有副作用的任意通用操作...您必须为每个要执行的新操作创建一个扩展方法(您还没有有一个扩展...) –

+0

绝对。正如我所说的,这是如果你真的想拥抱方法链接,而不是做某种事情。我希望你会有其他类正在做繁重的工作,所以扩展方法只是调用。所以,添加一个新的扩展方法并不是什么大不了的事,大概你不会每天都这样做。你会比你要写的方法更频繁地调用方法:)。而且,正如你所说,它更简洁。我宁愿写这样的代码,然后是所有'.Do()'。我的两分钱。 – aquinas