Linq IEnumerable extensions for void functions

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
2
down vote

favorite












I found myself wanting to use Linq to map void methods to an IEnumerable to modify all items. The existing Linq methods require a return variable when mapping, since they are based on Func.



So I decided to try my hand at creating some extension methods myself. This is the first time I've done anything like this, so if there are any pitfalls I'm missing, please do tell.



I created two extensions, one which applies a foreach loop to all elements, calling an Action<T> for each. The second one is basically the Zip extension, which allows for two IEnumerables to be iterated together and again maps a Action<T1,T2> to both of them.



public static void ForEachAction<T>(this IEnumerable<T> sequence, Action<T> action) 
foreach(T value in sequence)
action(value);



public static void ForEachActionZip<Tbase, Tsecond>(this IEnumerable<Tbase> sequence, IEnumerable<Tsecond> second, Action<Tbase, Tsecond> action)
sequence.Zip(second, (first, other) => new first, other ).ForEachAction(x => action(x.first, x.other));



You can then use this like so:



someList.ForEachAction(x => x.Update());


or



someList.ForEachActionZip(secondList, (a, b) => a.Update(b));






share|improve this question















  • 1




    Are you sure you want to mix functional programming with side effects? Why not use a foreach loop instead?
    – Pieter Witvoet
    Mar 23 at 14:11










  • @PieterWitvoet If I have two enumerables and I want to map some method with side-effects to both, using a foreach loop is kind of a pain. I don't really see a straightforward way to accomplish that.
    – JAD
    Mar 23 at 14:20






  • 1




    What about foreach (var item in first.Zip(second, ...)), where ... could produce a (value) tuple or an object of an existing or anonymous type? If used a lot, you could write a Zip extension method that doesn't require a Func<> argument. If it returned a value tuple, you could write foreach (var (item1, item2) in first.Zip(second)).
    – Pieter Witvoet
    Mar 23 at 14:51
















up vote
2
down vote

favorite












I found myself wanting to use Linq to map void methods to an IEnumerable to modify all items. The existing Linq methods require a return variable when mapping, since they are based on Func.



So I decided to try my hand at creating some extension methods myself. This is the first time I've done anything like this, so if there are any pitfalls I'm missing, please do tell.



I created two extensions, one which applies a foreach loop to all elements, calling an Action<T> for each. The second one is basically the Zip extension, which allows for two IEnumerables to be iterated together and again maps a Action<T1,T2> to both of them.



public static void ForEachAction<T>(this IEnumerable<T> sequence, Action<T> action) 
foreach(T value in sequence)
action(value);



public static void ForEachActionZip<Tbase, Tsecond>(this IEnumerable<Tbase> sequence, IEnumerable<Tsecond> second, Action<Tbase, Tsecond> action)
sequence.Zip(second, (first, other) => new first, other ).ForEachAction(x => action(x.first, x.other));



You can then use this like so:



someList.ForEachAction(x => x.Update());


or



someList.ForEachActionZip(secondList, (a, b) => a.Update(b));






share|improve this question















  • 1




    Are you sure you want to mix functional programming with side effects? Why not use a foreach loop instead?
    – Pieter Witvoet
    Mar 23 at 14:11










  • @PieterWitvoet If I have two enumerables and I want to map some method with side-effects to both, using a foreach loop is kind of a pain. I don't really see a straightforward way to accomplish that.
    – JAD
    Mar 23 at 14:20






  • 1




    What about foreach (var item in first.Zip(second, ...)), where ... could produce a (value) tuple or an object of an existing or anonymous type? If used a lot, you could write a Zip extension method that doesn't require a Func<> argument. If it returned a value tuple, you could write foreach (var (item1, item2) in first.Zip(second)).
    – Pieter Witvoet
    Mar 23 at 14:51












up vote
2
down vote

favorite









up vote
2
down vote

favorite











I found myself wanting to use Linq to map void methods to an IEnumerable to modify all items. The existing Linq methods require a return variable when mapping, since they are based on Func.



So I decided to try my hand at creating some extension methods myself. This is the first time I've done anything like this, so if there are any pitfalls I'm missing, please do tell.



I created two extensions, one which applies a foreach loop to all elements, calling an Action<T> for each. The second one is basically the Zip extension, which allows for two IEnumerables to be iterated together and again maps a Action<T1,T2> to both of them.



public static void ForEachAction<T>(this IEnumerable<T> sequence, Action<T> action) 
foreach(T value in sequence)
action(value);



public static void ForEachActionZip<Tbase, Tsecond>(this IEnumerable<Tbase> sequence, IEnumerable<Tsecond> second, Action<Tbase, Tsecond> action)
sequence.Zip(second, (first, other) => new first, other ).ForEachAction(x => action(x.first, x.other));



You can then use this like so:



someList.ForEachAction(x => x.Update());


or



someList.ForEachActionZip(secondList, (a, b) => a.Update(b));






share|improve this question











I found myself wanting to use Linq to map void methods to an IEnumerable to modify all items. The existing Linq methods require a return variable when mapping, since they are based on Func.



So I decided to try my hand at creating some extension methods myself. This is the first time I've done anything like this, so if there are any pitfalls I'm missing, please do tell.



I created two extensions, one which applies a foreach loop to all elements, calling an Action<T> for each. The second one is basically the Zip extension, which allows for two IEnumerables to be iterated together and again maps a Action<T1,T2> to both of them.



public static void ForEachAction<T>(this IEnumerable<T> sequence, Action<T> action) 
foreach(T value in sequence)
action(value);



public static void ForEachActionZip<Tbase, Tsecond>(this IEnumerable<Tbase> sequence, IEnumerable<Tsecond> second, Action<Tbase, Tsecond> action)
sequence.Zip(second, (first, other) => new first, other ).ForEachAction(x => action(x.first, x.other));



You can then use this like so:



someList.ForEachAction(x => x.Update());


or



someList.ForEachActionZip(secondList, (a, b) => a.Update(b));








share|improve this question










share|improve this question




share|improve this question









asked Mar 23 at 13:19









JAD

502317




502317







  • 1




    Are you sure you want to mix functional programming with side effects? Why not use a foreach loop instead?
    – Pieter Witvoet
    Mar 23 at 14:11










  • @PieterWitvoet If I have two enumerables and I want to map some method with side-effects to both, using a foreach loop is kind of a pain. I don't really see a straightforward way to accomplish that.
    – JAD
    Mar 23 at 14:20






  • 1




    What about foreach (var item in first.Zip(second, ...)), where ... could produce a (value) tuple or an object of an existing or anonymous type? If used a lot, you could write a Zip extension method that doesn't require a Func<> argument. If it returned a value tuple, you could write foreach (var (item1, item2) in first.Zip(second)).
    – Pieter Witvoet
    Mar 23 at 14:51












  • 1




    Are you sure you want to mix functional programming with side effects? Why not use a foreach loop instead?
    – Pieter Witvoet
    Mar 23 at 14:11










  • @PieterWitvoet If I have two enumerables and I want to map some method with side-effects to both, using a foreach loop is kind of a pain. I don't really see a straightforward way to accomplish that.
    – JAD
    Mar 23 at 14:20






  • 1




    What about foreach (var item in first.Zip(second, ...)), where ... could produce a (value) tuple or an object of an existing or anonymous type? If used a lot, you could write a Zip extension method that doesn't require a Func<> argument. If it returned a value tuple, you could write foreach (var (item1, item2) in first.Zip(second)).
    – Pieter Witvoet
    Mar 23 at 14:51







1




1




Are you sure you want to mix functional programming with side effects? Why not use a foreach loop instead?
– Pieter Witvoet
Mar 23 at 14:11




Are you sure you want to mix functional programming with side effects? Why not use a foreach loop instead?
– Pieter Witvoet
Mar 23 at 14:11












@PieterWitvoet If I have two enumerables and I want to map some method with side-effects to both, using a foreach loop is kind of a pain. I don't really see a straightforward way to accomplish that.
– JAD
Mar 23 at 14:20




@PieterWitvoet If I have two enumerables and I want to map some method with side-effects to both, using a foreach loop is kind of a pain. I don't really see a straightforward way to accomplish that.
– JAD
Mar 23 at 14:20




1




1




What about foreach (var item in first.Zip(second, ...)), where ... could produce a (value) tuple or an object of an existing or anonymous type? If used a lot, you could write a Zip extension method that doesn't require a Func<> argument. If it returned a value tuple, you could write foreach (var (item1, item2) in first.Zip(second)).
– Pieter Witvoet
Mar 23 at 14:51




What about foreach (var item in first.Zip(second, ...)), where ... could produce a (value) tuple or an object of an existing or anonymous type? If used a lot, you could write a Zip extension method that doesn't require a Func<> argument. If it returned a value tuple, you could write foreach (var (item1, item2) in first.Zip(second)).
– Pieter Witvoet
Mar 23 at 14:51










2 Answers
2






active

oldest

votes

















up vote
8
down vote













This is generally considered to be a bad idea. IEnumerable has deferred execution, which means that in your example, someList can be forced to enumerate any desired number of times.



As a consequence, it depends on the implementation behind the IEnumerable whether any changes applied by action will still be visible after your methods have run. There are two possibilities:




  1. someList is a materialized list (for example, List<SomeObject>). After running ForEachAction, a new enumeration of someList will produce the same, modified, objects.


  2. someList is an enumerable that produces new objects on each execution. After running ForEachAction, a new enumeration of someList will produce new objects. The changed objects are out of scope and will soon be garbage collected.

An example of the second option is an IQueryable against a SQL backend. When it is executed it will emit a SQL query that returns new objects from the database (caching as applied by many ORMs aside).



In that case it totally depends on what happens in action whether any effect of it is persistent. If action only modifies objects in someList its effect will be lost. If it uses objects in someList to change some external state (e.g. increment some sum value) its effect will persist.



As a conclusion, I wouldn't do this. If you want to apply void methods to any IEnumerable, first materialize it to a list and then apply existing methods. Instead of...



someList.ForEachAction(x => x.Update());


...you'd have...



var concreteList = someList.ToList();
concreteList.ForEach(x => x.Update());


Now continue working with concreteList so you'll be sure that the effect of x.Update() will remain visible in your code.






share|improve this answer























  • I think this will only be usable for reference types. For value types the items in concreteList will still remain unchanged.
    – Henrik Hansen
    Mar 23 at 15:17










  • @HenrikHansen But they probably won't try to modify value types. Anyway, as I said, this approach makes the effect dependent of what happens in the action, making it unpredictable as a whole.
    – Gert Arnold
    Mar 23 at 15:25










  • Your point in point 1 is that if I have say two expressions with the same enumerable, with the second one having side-effects like this, the first one could be deferred until after the second one executed, causing it to enumerate with the modified objects. Is that correct? If so, is that truly different with the .ForEach method?
    – JAD
    Mar 23 at 20:00










  • I'm not sure if I understand what you're asking, but the power of LINQ operations is that they can be chained without ever being executed. Only if in the end execution is forced by an immediately executing operation --like ToList, First, or Sum-- will the whole pipeline be enumerated. The whole point of my answer is: if you change state of objects produced by any IEnumerable (chained or not) you must make sure that you store these objects locally.
    – Gert Arnold
    Mar 24 at 10:22










  • @GertArnold But the intention for these methods is specifically to act as those immediately executing operations. They return void after all. As far as I am aware, the foreach loop in ForEachAction should force the enumerable to enumerate right?
    – JAD
    Mar 28 at 20:46

















up vote
2
down vote













If you want them to act a bit more like the Microsoft-supplied LINQ extension methods, you may want to consider some parameter checks (for example):



public static void ForEachAction<T>(this IEnumerable<T> sequence, Action<T> action) 
if (sequence== null)
throw new ArgumentNullException(nameof(sequence));


if (action== null)
throw new ArgumentNullException(nameof(action));


sequence.ForEachActionInternal(action);


private static void ForEachActionInternal<T>(this IEnumerable<T> sequence, Action<T> action)
foreach(T value in sequence)
action(value);




I've split it into two methods in case you decide to have your methods return a sequence of some sort lazily.






share|improve this answer





















    Your Answer




    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("mathjaxEditing", function ()
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    );
    );
    , "mathjax-editing");

    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "196"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f190306%2flinq-ienumerable-extensions-for-void-functions%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    8
    down vote













    This is generally considered to be a bad idea. IEnumerable has deferred execution, which means that in your example, someList can be forced to enumerate any desired number of times.



    As a consequence, it depends on the implementation behind the IEnumerable whether any changes applied by action will still be visible after your methods have run. There are two possibilities:




    1. someList is a materialized list (for example, List<SomeObject>). After running ForEachAction, a new enumeration of someList will produce the same, modified, objects.


    2. someList is an enumerable that produces new objects on each execution. After running ForEachAction, a new enumeration of someList will produce new objects. The changed objects are out of scope and will soon be garbage collected.

    An example of the second option is an IQueryable against a SQL backend. When it is executed it will emit a SQL query that returns new objects from the database (caching as applied by many ORMs aside).



    In that case it totally depends on what happens in action whether any effect of it is persistent. If action only modifies objects in someList its effect will be lost. If it uses objects in someList to change some external state (e.g. increment some sum value) its effect will persist.



    As a conclusion, I wouldn't do this. If you want to apply void methods to any IEnumerable, first materialize it to a list and then apply existing methods. Instead of...



    someList.ForEachAction(x => x.Update());


    ...you'd have...



    var concreteList = someList.ToList();
    concreteList.ForEach(x => x.Update());


    Now continue working with concreteList so you'll be sure that the effect of x.Update() will remain visible in your code.






    share|improve this answer























    • I think this will only be usable for reference types. For value types the items in concreteList will still remain unchanged.
      – Henrik Hansen
      Mar 23 at 15:17










    • @HenrikHansen But they probably won't try to modify value types. Anyway, as I said, this approach makes the effect dependent of what happens in the action, making it unpredictable as a whole.
      – Gert Arnold
      Mar 23 at 15:25










    • Your point in point 1 is that if I have say two expressions with the same enumerable, with the second one having side-effects like this, the first one could be deferred until after the second one executed, causing it to enumerate with the modified objects. Is that correct? If so, is that truly different with the .ForEach method?
      – JAD
      Mar 23 at 20:00










    • I'm not sure if I understand what you're asking, but the power of LINQ operations is that they can be chained without ever being executed. Only if in the end execution is forced by an immediately executing operation --like ToList, First, or Sum-- will the whole pipeline be enumerated. The whole point of my answer is: if you change state of objects produced by any IEnumerable (chained or not) you must make sure that you store these objects locally.
      – Gert Arnold
      Mar 24 at 10:22










    • @GertArnold But the intention for these methods is specifically to act as those immediately executing operations. They return void after all. As far as I am aware, the foreach loop in ForEachAction should force the enumerable to enumerate right?
      – JAD
      Mar 28 at 20:46














    up vote
    8
    down vote













    This is generally considered to be a bad idea. IEnumerable has deferred execution, which means that in your example, someList can be forced to enumerate any desired number of times.



    As a consequence, it depends on the implementation behind the IEnumerable whether any changes applied by action will still be visible after your methods have run. There are two possibilities:




    1. someList is a materialized list (for example, List<SomeObject>). After running ForEachAction, a new enumeration of someList will produce the same, modified, objects.


    2. someList is an enumerable that produces new objects on each execution. After running ForEachAction, a new enumeration of someList will produce new objects. The changed objects are out of scope and will soon be garbage collected.

    An example of the second option is an IQueryable against a SQL backend. When it is executed it will emit a SQL query that returns new objects from the database (caching as applied by many ORMs aside).



    In that case it totally depends on what happens in action whether any effect of it is persistent. If action only modifies objects in someList its effect will be lost. If it uses objects in someList to change some external state (e.g. increment some sum value) its effect will persist.



    As a conclusion, I wouldn't do this. If you want to apply void methods to any IEnumerable, first materialize it to a list and then apply existing methods. Instead of...



    someList.ForEachAction(x => x.Update());


    ...you'd have...



    var concreteList = someList.ToList();
    concreteList.ForEach(x => x.Update());


    Now continue working with concreteList so you'll be sure that the effect of x.Update() will remain visible in your code.






    share|improve this answer























    • I think this will only be usable for reference types. For value types the items in concreteList will still remain unchanged.
      – Henrik Hansen
      Mar 23 at 15:17










    • @HenrikHansen But they probably won't try to modify value types. Anyway, as I said, this approach makes the effect dependent of what happens in the action, making it unpredictable as a whole.
      – Gert Arnold
      Mar 23 at 15:25










    • Your point in point 1 is that if I have say two expressions with the same enumerable, with the second one having side-effects like this, the first one could be deferred until after the second one executed, causing it to enumerate with the modified objects. Is that correct? If so, is that truly different with the .ForEach method?
      – JAD
      Mar 23 at 20:00










    • I'm not sure if I understand what you're asking, but the power of LINQ operations is that they can be chained without ever being executed. Only if in the end execution is forced by an immediately executing operation --like ToList, First, or Sum-- will the whole pipeline be enumerated. The whole point of my answer is: if you change state of objects produced by any IEnumerable (chained or not) you must make sure that you store these objects locally.
      – Gert Arnold
      Mar 24 at 10:22










    • @GertArnold But the intention for these methods is specifically to act as those immediately executing operations. They return void after all. As far as I am aware, the foreach loop in ForEachAction should force the enumerable to enumerate right?
      – JAD
      Mar 28 at 20:46












    up vote
    8
    down vote










    up vote
    8
    down vote









    This is generally considered to be a bad idea. IEnumerable has deferred execution, which means that in your example, someList can be forced to enumerate any desired number of times.



    As a consequence, it depends on the implementation behind the IEnumerable whether any changes applied by action will still be visible after your methods have run. There are two possibilities:




    1. someList is a materialized list (for example, List<SomeObject>). After running ForEachAction, a new enumeration of someList will produce the same, modified, objects.


    2. someList is an enumerable that produces new objects on each execution. After running ForEachAction, a new enumeration of someList will produce new objects. The changed objects are out of scope and will soon be garbage collected.

    An example of the second option is an IQueryable against a SQL backend. When it is executed it will emit a SQL query that returns new objects from the database (caching as applied by many ORMs aside).



    In that case it totally depends on what happens in action whether any effect of it is persistent. If action only modifies objects in someList its effect will be lost. If it uses objects in someList to change some external state (e.g. increment some sum value) its effect will persist.



    As a conclusion, I wouldn't do this. If you want to apply void methods to any IEnumerable, first materialize it to a list and then apply existing methods. Instead of...



    someList.ForEachAction(x => x.Update());


    ...you'd have...



    var concreteList = someList.ToList();
    concreteList.ForEach(x => x.Update());


    Now continue working with concreteList so you'll be sure that the effect of x.Update() will remain visible in your code.






    share|improve this answer















    This is generally considered to be a bad idea. IEnumerable has deferred execution, which means that in your example, someList can be forced to enumerate any desired number of times.



    As a consequence, it depends on the implementation behind the IEnumerable whether any changes applied by action will still be visible after your methods have run. There are two possibilities:




    1. someList is a materialized list (for example, List<SomeObject>). After running ForEachAction, a new enumeration of someList will produce the same, modified, objects.


    2. someList is an enumerable that produces new objects on each execution. After running ForEachAction, a new enumeration of someList will produce new objects. The changed objects are out of scope and will soon be garbage collected.

    An example of the second option is an IQueryable against a SQL backend. When it is executed it will emit a SQL query that returns new objects from the database (caching as applied by many ORMs aside).



    In that case it totally depends on what happens in action whether any effect of it is persistent. If action only modifies objects in someList its effect will be lost. If it uses objects in someList to change some external state (e.g. increment some sum value) its effect will persist.



    As a conclusion, I wouldn't do this. If you want to apply void methods to any IEnumerable, first materialize it to a list and then apply existing methods. Instead of...



    someList.ForEachAction(x => x.Update());


    ...you'd have...



    var concreteList = someList.ToList();
    concreteList.ForEach(x => x.Update());


    Now continue working with concreteList so you'll be sure that the effect of x.Update() will remain visible in your code.







    share|improve this answer















    share|improve this answer



    share|improve this answer








    edited Mar 28 at 20:52


























    answered Mar 23 at 14:41









    Gert Arnold

    1,37211120




    1,37211120











    • I think this will only be usable for reference types. For value types the items in concreteList will still remain unchanged.
      – Henrik Hansen
      Mar 23 at 15:17










    • @HenrikHansen But they probably won't try to modify value types. Anyway, as I said, this approach makes the effect dependent of what happens in the action, making it unpredictable as a whole.
      – Gert Arnold
      Mar 23 at 15:25










    • Your point in point 1 is that if I have say two expressions with the same enumerable, with the second one having side-effects like this, the first one could be deferred until after the second one executed, causing it to enumerate with the modified objects. Is that correct? If so, is that truly different with the .ForEach method?
      – JAD
      Mar 23 at 20:00










    • I'm not sure if I understand what you're asking, but the power of LINQ operations is that they can be chained without ever being executed. Only if in the end execution is forced by an immediately executing operation --like ToList, First, or Sum-- will the whole pipeline be enumerated. The whole point of my answer is: if you change state of objects produced by any IEnumerable (chained or not) you must make sure that you store these objects locally.
      – Gert Arnold
      Mar 24 at 10:22










    • @GertArnold But the intention for these methods is specifically to act as those immediately executing operations. They return void after all. As far as I am aware, the foreach loop in ForEachAction should force the enumerable to enumerate right?
      – JAD
      Mar 28 at 20:46
















    • I think this will only be usable for reference types. For value types the items in concreteList will still remain unchanged.
      – Henrik Hansen
      Mar 23 at 15:17










    • @HenrikHansen But they probably won't try to modify value types. Anyway, as I said, this approach makes the effect dependent of what happens in the action, making it unpredictable as a whole.
      – Gert Arnold
      Mar 23 at 15:25










    • Your point in point 1 is that if I have say two expressions with the same enumerable, with the second one having side-effects like this, the first one could be deferred until after the second one executed, causing it to enumerate with the modified objects. Is that correct? If so, is that truly different with the .ForEach method?
      – JAD
      Mar 23 at 20:00










    • I'm not sure if I understand what you're asking, but the power of LINQ operations is that they can be chained without ever being executed. Only if in the end execution is forced by an immediately executing operation --like ToList, First, or Sum-- will the whole pipeline be enumerated. The whole point of my answer is: if you change state of objects produced by any IEnumerable (chained or not) you must make sure that you store these objects locally.
      – Gert Arnold
      Mar 24 at 10:22










    • @GertArnold But the intention for these methods is specifically to act as those immediately executing operations. They return void after all. As far as I am aware, the foreach loop in ForEachAction should force the enumerable to enumerate right?
      – JAD
      Mar 28 at 20:46















    I think this will only be usable for reference types. For value types the items in concreteList will still remain unchanged.
    – Henrik Hansen
    Mar 23 at 15:17




    I think this will only be usable for reference types. For value types the items in concreteList will still remain unchanged.
    – Henrik Hansen
    Mar 23 at 15:17












    @HenrikHansen But they probably won't try to modify value types. Anyway, as I said, this approach makes the effect dependent of what happens in the action, making it unpredictable as a whole.
    – Gert Arnold
    Mar 23 at 15:25




    @HenrikHansen But they probably won't try to modify value types. Anyway, as I said, this approach makes the effect dependent of what happens in the action, making it unpredictable as a whole.
    – Gert Arnold
    Mar 23 at 15:25












    Your point in point 1 is that if I have say two expressions with the same enumerable, with the second one having side-effects like this, the first one could be deferred until after the second one executed, causing it to enumerate with the modified objects. Is that correct? If so, is that truly different with the .ForEach method?
    – JAD
    Mar 23 at 20:00




    Your point in point 1 is that if I have say two expressions with the same enumerable, with the second one having side-effects like this, the first one could be deferred until after the second one executed, causing it to enumerate with the modified objects. Is that correct? If so, is that truly different with the .ForEach method?
    – JAD
    Mar 23 at 20:00












    I'm not sure if I understand what you're asking, but the power of LINQ operations is that they can be chained without ever being executed. Only if in the end execution is forced by an immediately executing operation --like ToList, First, or Sum-- will the whole pipeline be enumerated. The whole point of my answer is: if you change state of objects produced by any IEnumerable (chained or not) you must make sure that you store these objects locally.
    – Gert Arnold
    Mar 24 at 10:22




    I'm not sure if I understand what you're asking, but the power of LINQ operations is that they can be chained without ever being executed. Only if in the end execution is forced by an immediately executing operation --like ToList, First, or Sum-- will the whole pipeline be enumerated. The whole point of my answer is: if you change state of objects produced by any IEnumerable (chained or not) you must make sure that you store these objects locally.
    – Gert Arnold
    Mar 24 at 10:22












    @GertArnold But the intention for these methods is specifically to act as those immediately executing operations. They return void after all. As far as I am aware, the foreach loop in ForEachAction should force the enumerable to enumerate right?
    – JAD
    Mar 28 at 20:46




    @GertArnold But the intention for these methods is specifically to act as those immediately executing operations. They return void after all. As far as I am aware, the foreach loop in ForEachAction should force the enumerable to enumerate right?
    – JAD
    Mar 28 at 20:46












    up vote
    2
    down vote













    If you want them to act a bit more like the Microsoft-supplied LINQ extension methods, you may want to consider some parameter checks (for example):



    public static void ForEachAction<T>(this IEnumerable<T> sequence, Action<T> action) 
    if (sequence== null)
    throw new ArgumentNullException(nameof(sequence));


    if (action== null)
    throw new ArgumentNullException(nameof(action));


    sequence.ForEachActionInternal(action);


    private static void ForEachActionInternal<T>(this IEnumerable<T> sequence, Action<T> action)
    foreach(T value in sequence)
    action(value);




    I've split it into two methods in case you decide to have your methods return a sequence of some sort lazily.






    share|improve this answer

























      up vote
      2
      down vote













      If you want them to act a bit more like the Microsoft-supplied LINQ extension methods, you may want to consider some parameter checks (for example):



      public static void ForEachAction<T>(this IEnumerable<T> sequence, Action<T> action) 
      if (sequence== null)
      throw new ArgumentNullException(nameof(sequence));


      if (action== null)
      throw new ArgumentNullException(nameof(action));


      sequence.ForEachActionInternal(action);


      private static void ForEachActionInternal<T>(this IEnumerable<T> sequence, Action<T> action)
      foreach(T value in sequence)
      action(value);




      I've split it into two methods in case you decide to have your methods return a sequence of some sort lazily.






      share|improve this answer























        up vote
        2
        down vote










        up vote
        2
        down vote









        If you want them to act a bit more like the Microsoft-supplied LINQ extension methods, you may want to consider some parameter checks (for example):



        public static void ForEachAction<T>(this IEnumerable<T> sequence, Action<T> action) 
        if (sequence== null)
        throw new ArgumentNullException(nameof(sequence));


        if (action== null)
        throw new ArgumentNullException(nameof(action));


        sequence.ForEachActionInternal(action);


        private static void ForEachActionInternal<T>(this IEnumerable<T> sequence, Action<T> action)
        foreach(T value in sequence)
        action(value);




        I've split it into two methods in case you decide to have your methods return a sequence of some sort lazily.






        share|improve this answer













        If you want them to act a bit more like the Microsoft-supplied LINQ extension methods, you may want to consider some parameter checks (for example):



        public static void ForEachAction<T>(this IEnumerable<T> sequence, Action<T> action) 
        if (sequence== null)
        throw new ArgumentNullException(nameof(sequence));


        if (action== null)
        throw new ArgumentNullException(nameof(action));


        sequence.ForEachActionInternal(action);


        private static void ForEachActionInternal<T>(this IEnumerable<T> sequence, Action<T> action)
        foreach(T value in sequence)
        action(value);




        I've split it into two methods in case you decide to have your methods return a sequence of some sort lazily.







        share|improve this answer













        share|improve this answer



        share|improve this answer











        answered Mar 23 at 13:47









        Jesse C. Slicer

        10.9k2738




        10.9k2738






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f190306%2flinq-ienumerable-extensions-for-void-functions%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            Greedy Best First Search implementation in Rust

            Function to Return a JSON Like Objects Using VBA Collections and Arrays

            C++11 CLH Lock Implementation