-1

I have been asked this question in an interview.

Let’s say there is a c# collection that contains items, all of which implement an interface IUpdatable that contains a method Update(). How can one call the update method on all items in a single statement, a one liner in c#?

I did try the foreach on collection and invoking the update() on every item that way. Interviewer said that it is more of a junior developer’s style. He wants something short, in one line.

I didn’t realise it at the time, but there are 2 scenarios here. If the collection is not already of type collection<IUpdatable>, a type casting step is needed first to convert the collection from say collection<object> to collection<IUpdatable>. Any shortcuts for performing this?

  • Was there a specific type of collection specified, or a specific collection interface used? – ProgrammingLlama Apr 16 '19 at 00:53
  • Hmm. Could you maybe do this with a lambda? – Scuba Steve Apr 16 '19 at 00:58
  • 1
    Did you use foreach loop or the extension method? I would ignore his comment about it being junior dev's style though, you can even write your own loop implementation using reflections....then no casting required... – peeyush singh Apr 16 '19 at 00:58
  • one liner could be many statements. Probably the collection itself can implement IUpdatable or use a static import to enrich it ? – Dr Phil Apr 16 '19 at 00:59
  • The casting "shortcut" would be `items.Cast()`, assuming you know the conversions will be ok. – Evan Trimboli Apr 16 '19 at 01:01
  • @Scuba Steve , yes he was asking me about linq and lambdas when this question came up! – user1074213 Apr 16 '19 at 01:10
  • collection.Cast().ToList().ForEach( e => e.Update() ); – Sir Rufo Apr 16 '19 at 01:12
  • @John, I’ve edited the question to escape the missing tags. Please take a look now – user1074213 Apr 16 '19 at 01:12
  • 3
    foreach is actually the right tool for this thing, have a look at https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/ – Antonín Lejsek Apr 16 '19 at 01:13
  • @AntonínLejsek - Yes I agree. While you might be able to accomplish this with a lambda, that's probably not the ideal approach. Lambdas can produce very readable code when used properly, but in this scenario, the best approach is also the simplest. That "junior engineers" comment is kinda off base. C# lambdas are amazing tools, but don't use a hammer when the job calls for a screwdriver! – Scuba Steve Apr 17 '19 at 02:54

2 Answers2

2

I would disagree with your interviewer, because some things which may look simple today become a headache for other developers tomorrow.

I would suggest to use List<T>.ForEach method

Documentation says:

Performs the specified action on each element of the List.

i.e. myList.ForEach(p => myFunc(p)); But it is only available on List<T>, not IList<T> or IEnumerable<T>

So, if your collection is different, you can do a trick like that myList.ToList().ForEach(e => ...);

Update

Yes, you may want to cast items to IUpdatable if needed i.e. Enumerable.Cast<T> or Select(e => (IUpdatable)e)

Also, you can use TPL and things like Parallel.ForEach

Parallel.ForEach(myList, p =>
{
    //Your stuff
});

but I'm not sure if parallel execution was on the table

I hope it helps

Community
  • 1
  • 1
Pavel Kovalev
  • 7,521
  • 5
  • 45
  • 67
1

Expected answer to the interview question:

One should not use LINQ to call methods that only produce side-effects. So it would be better not to do that. If required List.ForEach is the idiomatic way to call methods when you don't care about result, but since we have a collection that may not be a list it will require extra allocations (in addition to casts):

 collection.Cast<IUpdatable>().ToList().ForEach(x => x.Update());

To cast one can use Enumerable.Cast<T>, Enumerable.OfType<T> or just Select(x => (IUpdatable)x).

Less idiomatic way would be to fake return value (or ignore one if Update() has it) in regular LINQ query. Note that we'll need to force evaluation of query in some way, like .ToList() or better .All():

  collection.Cast<IUpdatable>()
       .Select(x => { x.Update(); return true;})
       .All(x=>x); // to force evaluation without creating extra list

If collection is already of type IEnumerable<IUpdatable> (or any type that derived from IUpdatable) you don't need Cast (or OfType).

If that will be common operation creating custom extension method that clearly designed to call an action on every enumerable would be better approach than two shown earlier.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179