I have come across some code that locks on an Action and have found that it does not work. Here is a (simplified and silly) version of the code:
class Program
{
static void Main(string[] args)
{
var settings = new Settings(0);
Action<int> threadAction = i =>
{
BusyBody.DoSomething(settings.GetANumber, settings.SetANumber, i);
};
ThreadPool.QueueUserWorkItem(delegate { threadAction(1); });
ThreadPool.QueueUserWorkItem(delegate { threadAction(2); });
Console.ReadLine();
}
class Settings
{
int i;
public Settings(int i)
{
this.i = i;
}
public int GetANumber() => i;
public void SetANumber(int i) => this.i = i;
}
class BusyBody
{
public static void DoSomething(Func<int> getInt, Action<int> setInt, int i)
{
lock (setInt)
{
Console.WriteLine("Getting int: " + getInt());
Console.WriteLine("i " + i);
setInt(i);
Console.WriteLine("set");
}
}
}
}
I would expect this to produce the following output:
Getting int: 0
i 1
set
Getting int: 1
i 2
set
OR
Getting int: 0
i 2
set
Getting int: 2
i 1
set
Depending on whichever thread gets through the lock first. However this isn't what I am seeing. Instead I see:
Getting int: 0
i 2
Getting int: 0
i 1
set
set
It looks like both threads enter the lock. Why does this happen? The Action being locked is the same method from the same object so shouldn't the references be the same?
Any help would be appreciated. Thanks!
The problem here is that you're locking on two different objects.
This line:
BusyBody.DoSomething(settings.GetANumber, settings.SetANumber, i);
is short for this:
BusyBody.DoSomething(new Func<int>(settings.GetANumber), new Action<int>(settings.SetANumber), i);
The two new Func<int>(...) and new Action<int>(...) expressions will produce new delegate objects on each call, thus you're not locking on the same object instance.
If you want to share these objects they have to be created once:
...
Func<int> getANumber = settings.GetANumber;
Action<int> setANumber = settings.SetANumber;
Action<int> threadAction = i =>
{
BusyBody.DoSomething(getANumber, setANumber, i);
};
...
When you cast a method to an Action multiple times (when you pass settings.SetANumber), that does not mean that you get the same Action object. You get multiple Action objects that do the same thing.
Try this:
Action<int> set_action = settings.SetANumber;
Action<int> threadAction = i =>
{
BusyBody.DoSomething(settings.GetANumber, set_action, i);
};
This makes sure that you have a single Action object.
Related
I need to display items satisfying some conditions.
public BindableCollection<BaseTreeItemViewModel> TreeItems
{
get
{
if (_logicTest)
return (BindableCollection<BaseTreeItemViewModel>)_treeItems.Where(n => _logicTest);
else
return _treeItems;
}
set
{
_treeItems = value;
NotifyOfPropertyChange(() => TreeItems);
}
}
In fact in Where clause there will be different test (n.Header == "ABC"), but it is not working even for _logicTest, which we know is true while launching the line with Where.
_treeItems contains about 20 elements and for _logicTest=false they are all returned. On the other hand for _logicTest=true function returns empty collection.
Where is the mistake?
Thanks in advance for any help.
Edit
As #Robert.S suggested , I've used:
return new BindableCollection<BaseTreeItemViewModel>(_treeItems.Where(n => _logicTest));
and it worked. Thanks.
What is _logicTest? A property? If so it might change while the collection is evaluated. Moreover the return value of Where is an IEnumerable<T>. The real values will only be evaluated if you use the collection (e.g. in a foreach loop).
You can try to add a ToList() or ToArray() at the end of the Where. This way the collection is evaluated immediately and you can see if there are really no items at the point of time when the getter is executed.
Another option is the VS debugger. In the watch table you can evaluate the collection with the small refresh icon. This way you also can see the "real" items.
But if you use the collection later (e.g. in a foreach loop) and _logicTest is not true anymore, the collection may be empty.
Here is a simple example:
class Program
{
static bool _logicTest = false;
static int[] items = new int[] { 1, 2, 3 };
static void Main(string[] args)
{
_logicTest = true;
var foo = items.Where(n => _logicTest);
_logicTest = false;
Console.WriteLine(foo.Count());
_logicTest = true;
Console.WriteLine(foo.Count());
}
}
The output will be:
0
3
In the above example Count() will evaluate the collection to determine its size. You can see that the value of _logicTest is evaluated at this very moment and not when Where was called.
A possible workaround for your case would be a local variable:
get
{
bool logicTest = _logicTest;
if (logicTest)
return (BindableCollection<BaseTreeItemViewModel>)_treeItems.Where(n => logicTest);
else
return _treeItems;
}
The local variable will not change. But you should store the property value in another variable. Cause if you access the property when _logicTest is false, you will run into the same problem of course.
Here is the above example with the workaround:
class Program
{
static bool _logicTest = false;
static int[] items = new int[] { 1, 2, 3 };
static void Main(string[] args)
{
_logicTest = true;
var foo = items.Where(n => _logicTest);
var bar = Items;
_logicTest = false;
Console.WriteLine(foo.Count());
Console.WriteLine(bar.Count());
_logicTest = true;
Console.WriteLine(foo.Count());
Console.WriteLine(bar.Count());
}
static IEnumerable<int> Items
{
get
{
bool logicTest = _logicTest;
return items.Where(n => logicTest);
}
}
}
The output is 0 3 3 3
I've got a work around for this issue, but I'm trying to figure out why it works . Basically, I'm looping through a list of structs using foreach. If I include a LINQ statement that references the current struct before I call a method of the struct, the method is unable to modify the members of the struct. This happens regardless of whether the LINQ statement is even called. I was able to work around this by assigning the value I was looking for to a variable and using that in the LINQ, but I would like to know what is causing this. Here's an example I created.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WeirdnessExample
{
public struct RawData
{
private int id;
public int ID
{
get{ return id;}
set { id = value; }
}
public void AssignID(int newID)
{
id = newID;
}
}
public class ProcessedData
{
public int ID { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<ProcessedData> processedRecords = new List<ProcessedData>();
processedRecords.Add(new ProcessedData()
{
ID = 1
});
List<RawData> rawRecords = new List<RawData>();
rawRecords.Add(new RawData()
{
ID = 2
});
int i = 0;
foreach (RawData rawRec in rawRecords)
{
int id = rawRec.ID;
if (i < 0 || i > 20)
{
List<ProcessedData> matchingRecs = processedRecords.FindAll(mr => mr.ID == rawRec.ID);
}
Console.Write(String.Format("With LINQ: ID Before Assignment = {0}, ", rawRec.ID)); //2
rawRec.AssignID(id + 8);
Console.WriteLine(String.Format("ID After Assignment = {0}", rawRec.ID)); //2
i++;
}
rawRecords = new List<RawData>();
rawRecords.Add(new RawData()
{
ID = 2
});
i = 0;
foreach (RawData rawRec in rawRecords)
{
int id = rawRec.ID;
if (i < 0)
{
List<ProcessedData> matchingRecs = processedRecords.FindAll(mr => mr.ID == id);
}
Console.Write(String.Format("With LINQ: ID Before Assignment = {0}, ", rawRec.ID)); //2
rawRec.AssignID(id + 8);
Console.WriteLine(String.Format("ID After Assignment = {0}", rawRec.ID)); //10
i++;
}
Console.ReadLine();
}
}
}
Okay, I've managed to reproduce this with a rather simpler test program, as shown below, and I now understand it. Admittedly understanding it doesn't make me feel any less nauseous, but hey... Explanation after code.
using System;
using System.Collections.Generic;
struct MutableStruct
{
public int Value { get; set; }
public void AssignValue(int newValue)
{
Value = newValue;
}
}
class Test
{
static void Main()
{
var list = new List<MutableStruct>()
{
new MutableStruct { Value = 10 }
};
Console.WriteLine("Without loop variable capture");
foreach (MutableStruct item in list)
{
Console.WriteLine("Before: {0}", item.Value); // 10
item.AssignValue(30);
Console.WriteLine("After: {0}", item.Value); // 30
}
// Reset...
list[0] = new MutableStruct { Value = 10 };
Console.WriteLine("With loop variable capture");
foreach (MutableStruct item in list)
{
Action capture = () => Console.WriteLine(item.Value);
Console.WriteLine("Before: {0}", item.Value); // 10
item.AssignValue(30);
Console.WriteLine("After: {0}", item.Value); // Still 10!
}
}
}
The difference between the two loops is that in the second one, the loop variable is captured by a lambda expression. The second loop is effectively turned into something like this:
// Nested class, would actually have an unspeakable name
class CaptureHelper
{
public MutableStruct item;
public void Execute()
{
Console.WriteLine(item.Value);
}
}
...
// Second loop in main method
foreach (MutableStruct item in list)
{
CaptureHelper helper = new CaptureHelper();
helper.item = item;
Action capture = helper.Execute;
MutableStruct tmp = helper.item;
Console.WriteLine("Before: {0}", tmp.Value);
tmp = helper.item;
tmp.AssignValue(30);
tmp = helper.item;
Console.WriteLine("After: {0}", tmp.Value);
}
Now of course each time we copy the variable out of helper we get a fresh copy of the struct. This should normally be fine - the iteration variable is read-only, so we'd expect it not to change. However, you have a method which changes the contents of the struct, causing the unexpected behaviour.
Note that if you tried to change the property, you'd get a compile-time error:
Test.cs(37,13): error CS1654: Cannot modify members of 'item' because it is a
'foreach iteration variable'
Lessons:
Mutable structs are evil
Structs which are mutated by methods are doubly evil
Mutating a struct via a method call on an iteration variable which has been captured is triply evil to the extent of breakage
It's not 100% clear to me whether the C# compiler is behaving as per the spec here. I suspect it is. Even if it's not, I wouldn't want to suggest the team should put any effort into fixing it. Code like this is just begging to be broken in subtle ways.
Ok. We definitely have an issues here but I suspect that this issue not with closures per se but with foreach implementation instead.
C# 4.0 specification stated (8.8.4 The foreach statement) that "the iteration variable corresponds to a read-only local variable with a scope that extends over the embedded statement". That's why we can't change loop variable or increment it's property (as Jon already stated):
struct Mutable
{
public int X {get; set;}
public void ChangeX(int x) { X = x; }
}
var mutables = new List<Mutable>{new Mutable{ X = 1 }};
foreach(var item in mutables)
{
// Illegal!
item = new Mutable();
// Illegal as well!
item.X++;
}
In this regard read-only loop variables behave almost exactly the same as any readonly field (in terms of accessing this variable outside of the constructor):
We can't change readonly field outside of the constructor
We can't change property of the read-only field of value type
We're treating readonly fields as values that leads to using a temporary copy every time we accessing readonly field of value type.
.
class MutableReadonly
{
public readonly Mutable M = new Mutable {X = 1};
}
// Somewhere in the code
var mr = new MutableReadonly();
// Illegal!
mr.M = new Mutable();
// Illegal as well!
mr.M.X++;
// Legal but lead to undesired behavior
// becaues mr.M.X remains unchanged!
mr.M.ChangeX(10);
There is a plenty of issues related to mutable value types and one of them related to the last behavior: changing readonly struct via mutator method (like ChangeX) lead to obscure behavior because we'll modify a copy but not an readonly object itself:
mr.M.ChangeX(10);
Is equivalent to:
var tmp = mr.M;
tmp.ChangeX(10);
If loop variable treated by the C# compiler as a read-only local variable, than its seems reasonable to expect the same behavior for them as for read-only fields.
Right now loop variable in the simple loop (without any closures) behaves almost the same as a read-only field except copying it for every access. But if code changes and closure comes to play, loop variable starts behaving like pure read-only variable:
var mutables = new List<Mutable> { new Mutable { X = 1 } };
foreach (var m in mutables)
{
Console.WriteLine("Before change: {0}", m.X); // X = 1
// We'll change loop variable directly without temporary variable
m.ChangeX(10);
Console.WriteLine("After change: {0}", m.X); // X = 10
}
foreach (var m in mutables)
{
// We start treating m as a pure read-only variable!
Action a = () => Console.WriteLine(m.X));
Console.WriteLine("Before change: {0}", m.X); // X = 1
// We'll change a COPY instead of a m variable!
m.ChangeX(10);
Console.WriteLine("After change: {0}", m.X); // X = 1
}
Unfortunately I can't find strict rules how read-only local variables should behave but its clear that this behavior is different based on loop body: we're not copying to locals for every access in simple loop, but we DO this if the loop body closes over loop variable.
We all know that Closing over loop variable considered harmful and that loop implementation was changed in the C# 5.0. Simple way to fix that old issue in pre C# 5.0 era was introducing local variable, but interesting that introducing local variable in this our case will change behavior as well:
foreach (var mLoop in mutables)
{
// Introducing local variable!
var m = mLoop;
// We're capturing local variable instead of loop variable
Action a = () => Console.WriteLine(m.X));
Console.WriteLine("Before change: {0}", m.X); // X = 1
// We'll roll back this behavior and will change
// value type directly in the closure without making a copy!
m.ChangeX(10); // X = 10 !!
Console.WriteLine("After change: {0}", m.X); // X = 1
}
Actually this means that C# 5.0 has very subtle breaking change because no one will introduce a local variable any more (and even tools like ReSharper stops warning about it in VS2012 because its not an issue).
I'm OK with both behaviors but inconsistency seems strange.
I suspect this has to do with how lambda expressions are evaluated. See this question and its answer for more details.
Question:
When using lambda expressions or anonymous methods in C#, we have to be wary of the access to modified closure pitfall. For example:
foreach (var s in strings)
{
query = query.Where(i => i.Prop == s); // access to modified closure
Due to the modified closure, the above code will cause all of the Where clauses on the query to be based on the final value of s.
Answer:
This is one of the worst "gotchas" in C#, and we are going to take the breaking change to fix it. In C# 5 the foreach loop variable will be logically inside the body of the loop, and therefore closures will get a fresh copy every time.
Just to accomplish Sergey's post, I wanna to add following example with manual closure, that demonstrates compiler's behavior. Of course compiler might have any other implementation that satisfies readonly requirement of captured within foreach statement variable.
static void Main()
{
var list = new List<MutableStruct>()
{
new MutableStruct { Value = 10 }
};
foreach (MutableStruct item in list)
{
var c = new Closure(item);
Console.WriteLine(c.Item.Value);
Console.WriteLine("Before: {0}", c.Item.Value); // 10
c.Item.AssignValue(30);
Console.WriteLine("After: {0}", c.Item.Value); // Still 10!
}
}
class Closure
{
public Closure(MutableStruct item){
Item = item;
}
//readonly modifier is mandatory
public readonly MutableStruct Item;
public void Foo()
{
Console.WriteLine(Item.Value);
}
}
This might solve your issue. It swaps out foreach for a for and makes the struct immutable.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WeirdnessExample
{
public struct RawData
{
private readonly int id;
public int ID
{
get{ return id;}
}
public RawData(int newID)
{
id = newID;
}
}
public class ProcessedData
{
private readonly int id;
public int ID
{
get{ return id;}
}
public ProcessedData(int newID)
{
id = newID;
}
}
class Program
{
static void Main(string[] args)
{
List<ProcessedData> processedRecords = new List<ProcessedData>();
processedRecords.Add(new ProcessedData(1));
List<RawData> rawRecords = new List<RawData>();
rawRecords.Add(new RawData(2));
for (int i = 0; i < rawRecords.Count; i++)
{
RawData rawRec = rawRecords[i];
int id = rawRec.ID;
if (i < 0 || i > 20)
{
RawData rawRec2 = rawRec;
List<ProcessedData> matchingRecs = processedRecords.FindAll(mr => mr.ID == rawRec2.ID);
}
Console.Write(String.Format("With LINQ: ID Before Assignment = {0}, ", rawRec.ID)); //2
rawRec = new RawData(rawRec.ID + 8);
Console.WriteLine(String.Format("ID After Assignment = {0}", rawRec.ID)); //2
i++;
}
rawRecords = new List<RawData>();
rawRecords.Add(new RawData(2));
for (int i = 0; i < rawRecords.Count; i++)
{
RawData rawRec = rawRecords[i];
int id = rawRec.ID;
if (i < 0)
{
List<ProcessedData> matchingRecs = processedRecords.FindAll(mr => mr.ID == id);
}
Console.Write(String.Format("With LINQ: ID Before Assignment = {0}, ", rawRec.ID)); //2
rawRec = new RawData(rawRec.ID + 8);
Console.WriteLine(String.Format("ID After Assignment = {0}", rawRec.ID)); //10
i++;
}
Console.ReadLine();
}
}
}
I have a list of objects (using anonymous types) containing a decimal and an integer ID, and I'm building a function to take the sum of the decimals contained within all unique objects in the list.
This is the line of code I wrote:
var result = (objectList.Any()) ? objectList.Distinct().Sum(x => x.DecimalValue) : 0;
However, it always returns a decimal with the value 0, even though it should be returning the sum - objectList contains five identical objects in my example, so it should return the DecimalValue.
If I replace it with these two lines of code, however, it returns the DecimalValue:
decimal result = 0;
if (objectList.Any()) result = objectList.Distinct().Sum(x => x.DecimalValue);
Why does the second set of lines work, but the first line returns the wrong value? objectList.Any() is true, so it shouldn't be using the false assignment.
Update: I generated the list of anonymous types using this line of code:
var objectList = _ms.Read(cmd, x => new { DecimalValue = x.Field<decimal>("SomeColumnName"), Id = x.Field<int>("SomeColumnId") }).ToList();
_ms is a DAO for MS SQL, and it's running the lambda function that converts each datarow of the results to the anonymous typed object, which is returned in a list. I actually haven't been able to figure out how to build a list of those objects manually.
Another Update: Using Reed Copsey's reply below, I created the list manually in a way that duplicates the list that I'm getting, and I can reproduce the error with the manually created list:
var objectList = Enumerable.Range(0, 5).Select(i => new { DecimalValue = (decimal)31.45, Id = 3 }).ToList();
var result = (objectList.Any()) ? objectList.Distinct().Sum(x => x.DecimalValue) : 0;
I also tried removing the cast to decimal, and the issue is still present.
Another Update: After some further debugging I realized something I've never come across before. I set a breakpoint immediately after the line of code I mentioned that was having problems in each case. For the workaround, it returned 31.45. For the problem line, it returned 0. When I stepped into the next line, and looked at the variable again, it said 31.45. The line I set the breakpoint on did not access or modify the variable.
It would seem that both lines work, but that the debugger showed that it did not until I moved at least two lines after the code. I've never come across that before, but it shows that the code indeed does work.
There is no problem with your statement.
The issue is elsewhere, most likely in how you're constructing objectList.
For example, the following works exactly as expected, and prints "0.6" (as would be expected):
namespace Test
{
using System;
using System.Linq;
internal class TestCompile
{
private static void Main(string[] args)
{
var objectList = Enumerable.Range(0, 3).Select(i => new { ID = i, DecimalValue = i / 5.0m }).ToList();
decimal result = objectList.Any() ? objectList.Distinct().Sum(x => x.DecimalValue) : 0;
Console.WriteLine(result);
Console.ReadKey();
}
}
}
Update:
In response to your update, this also works perfectly:
private static void Main(string[] args)
{
var objectList = Enumerable.Range(0, 5).Select(i => new { DecimalValue = (decimal)31.45, Id = 3 }).ToList();
var result = (objectList.Any()) ? objectList.Distinct().Sum(x => x.DecimalValue) : 0;
Console.WriteLine(result);
Console.ReadKey();
}
It is using the exact code you pasted, and reports 31.45, as expected (due to the unique constraint). Note that, personally, I would use 31.45m instead of the cast, but it works even as written...
For what it's worth, your code works though I had to make up my own type.
[Test]
public void X()
{
var objectList = Enumerable.Range(1, 10).Select(d => new {DecimalValue = Convert.ToDecimal(d)});
var result = (objectList.Any()) ? objectList.Distinct().Sum(x => x.DecimalValue) : 0;
Assert.AreEqual(55, result);
Assert.AreEqual(typeof (decimal), result.GetType());
}
Too big for a comment so CW it is.
I just compiled a code
public class ObjectValue
{
public Decimal DecimalValue { get; set; }
}
class Program
{
static void Main(string[] args)
{
var objectList = new List<ObjectValue>() { new ObjectValue() { DecimalValue = 5 }, new ObjectValue() { DecimalValue = 5 } ,
new ObjectValue() { DecimalValue = 5 }};
var result = (objectList.Any()) ? objectList.Distinct().Sum(x => x.DecimalValue) : 0;
decimal resultDecimal = 0;
if (objectList.Any())
resultDecimal = objectList.Distinct().Sum(x => x.DecimalValue);
}
}
And result and resultDecimal are 15, in my case. I have coherent result in both cases provided, as I expected. So the error is somewhere else.
I currently have a log object I'd like to remove objects from, based on a LINQ query. I would like to remove all records in the log if the sum of the versions within a program are greater than 60. Currently I'm pretty confident that this'll work, but it seems kludgy:
for (int index = 0; index < 4; index++)
{
Log.RemoveAll(log =>
(log.Program[index].Version[0].Value +
log.Program[index].Version[1].Value +
log.Program[index].Version[2].Value ) > 60);
}
The Program is an array of 4 values and version has an array of 3 values. Is there a more simple way to do this RemoveAll in LINQ without using the for loop?
Thanks for any help in advance!
EDIT:
Unfortunately the type of variable that Program and Version are based off of (which is a constraint of the framework I'm working in) restricts us such that I cannot access the "Any" member. I however confirmed that tzaman's solution works if you have lists by creating some sample code. I'm restricted to array-like variables (see the commented out areas)
// I'm restricted to Arrays, but if I had lists, this would work.
internal class MyLogCollection
{
List<MyLog> MyListOfZones = new List<MyLog>();
public void TestRemove()
{
// Original Implementation
for (int i = 0; i < 4; i++)
{
MyListOfZones.RemoveAll(log => (log.MyZoneArray[0].MyVersionArray[0].Value +
log.MyZoneArray[0].MyVersionArray[1].Value +
log.MyZoneArray[0].MyVersionArray[2].Value) > 60);
//"Any" method is not available off of intellisense scope on MyZoneArray
}
// Better Implementation (thanks tzaman!)
MyListOfZones.RemoveAll(log => (log.MyZoneArray.Any(prog =>
prog.MyVersionArray.Sum(ver => ver.Value) > 60)));
}
}
internal class MyLog
{
//public MyZone[] MyZoneArray = new MyZone[4];
public List<MyZone> MyZoneArray = new List<MyZone>(4);
}
internal class MyZone
{
//public MyVersion[] MyVersionArray = new MyVersion[3];
public List<MyVersion> MyVersionArray = new List<MyVersion>(3);
}
internal class MyVersion
{
public byte Value { get; set;}
}
Thanks tzaman!
This should do it, I think:
Log.RemoveAll(log =>
log.Program.Any(prog =>
prog.Version.Sum(ver => ver.Value) > 60));
EDIT: Okay, so here's how to add extension methods to get IEnumerables from your indexable "array-like" objects, so that you can use LINQ on them:
static class MyExtensions
{
public static IEnumerable<MyZone> Enumerate(this MyZoneArray zone)
{
for (int i = 0; i < zone.Length; i++)
yield return zone[i];
}
public static IEnumerable<MyVersion> Enumerate(this MyVersionArray version)
{
for (int i = 0; i < version.Length; i++)
yield return version[i]
}
}
I'm assuming the MyZoneArray and MyVersionArray types have a Length field, but if not you could just put in 4 and 3 over there. With these in place, you can now call the Enumerate() function on the collection object to get an IEnumerable version of the collection, with all the associated LINQy goodness attached: log.MyZoneArray.Enumerate().Any( ... )
Is there a way to do foreach style iteration over parallel enumerables in C#? For subscriptable lists, I know one could use a regular for loop iterating an int over the index range, but I really prefer foreach to for for a number of reasons.
Bonus points if it works in C# 2.0
.NET 4's BlockingCollection makes this pretty easy. Create a BlockingCollection, return its .GetConsumingEnumerable() in the enumerable method. Then the foreach simply adds to the blocking collection.
E.g.
private BlockingCollection<T> m_data = new BlockingCollection<T>();
public IEnumerable<T> GetData( IEnumerable<IEnumerable<T>> sources )
{
Task.Factory.StartNew( () => ParallelGetData( sources ) );
return m_data.GetConsumingEnumerable();
}
private void ParallelGetData( IEnumerable<IEnumerable<T>> sources )
{
foreach( var source in sources )
{
foreach( var item in source )
{
m_data.Add( item );
};
}
//Adding complete, the enumeration can stop now
m_data.CompleteAdding();
}
Hope this helps.
BTW I posted a blog about this last night
Andre
Short answer, no. foreach works on only one enumerable at a time.
However, if you combine your parallel enumerables into a single one, you can foreach over the combined. I am not aware of any easy, built in method of doing this, but the following should work (though I have not tested it):
public IEnumerable<TSource[]> Combine<TSource>(params object[] sources)
{
foreach(var o in sources)
{
// Choose your own exception
if(!(o is IEnumerable<TSource>)) throw new Exception();
}
var enums =
sources.Select(s => ((IEnumerable<TSource>)s).GetEnumerator())
.ToArray();
while(enums.All(e => e.MoveNext()))
{
yield return enums.Select(e => e.Current).ToArray();
}
}
Then you can foreach over the returned enumerable:
foreach(var v in Combine(en1, en2, en3))
{
// Remembering that v is an array of the type contained in en1,
// en2 and en3.
}
Zooba's answer is good, but you might also want to look at the answers to "How to iterate over two arrays at once".
I wrote an implementation of EachParallel() from the .NET4 Parallel library. It is compatible with .NET 3.5: Parallel ForEach Loop in C# 3.5
Usage:
string[] names = { "cartman", "stan", "kenny", "kyle" };
names.EachParallel(name =>
{
try
{
Console.WriteLine(name);
}
catch { /* handle exception */ }
});
Implementation:
/// <summary>
/// Enumerates through each item in a list in parallel
/// </summary>
public static void EachParallel<T>(this IEnumerable<T> list, Action<T> action)
{
// enumerate the list so it can't change during execution
list = list.ToArray();
var count = list.Count();
if (count == 0)
{
return;
}
else if (count == 1)
{
// if there's only one element, just execute it
action(list.First());
}
else
{
// Launch each method in it's own thread
const int MaxHandles = 64;
for (var offset = 0; offset < list.Count() / MaxHandles; offset++)
{
// break up the list into 64-item chunks because of a limitiation // in WaitHandle
var chunk = list.Skip(offset * MaxHandles).Take(MaxHandles);
// Initialize the reset events to keep track of completed threads
var resetEvents = new ManualResetEvent[chunk.Count()];
// spawn a thread for each item in the chunk
int i = 0;
foreach (var item in chunk)
{
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback((object data) =>
{
int methodIndex = (int)((object[])data)[0];
// Execute the method and pass in the enumerated item
action((T)((object[])data)[1]);
// Tell the calling thread that we're done
resetEvents[methodIndex].Set();
}), new object[] { i, item });
i++;
}
// Wait for all threads to execute
WaitHandle.WaitAll(resetEvents);
}
}
}
If you want to stick to the basics - I rewrote the currently accepted answer in a simpler way:
public static IEnumerable<TSource[]> Combine<TSource> (this IEnumerable<IEnumerable<TSource>> sources)
{
var enums = sources
.Select (s => s.GetEnumerator ())
.ToArray ();
while (enums.All (e => e.MoveNext ())) {
yield return enums.Select (e => e.Current).ToArray ();
}
}
public static IEnumerable<TSource[]> Combine<TSource> (params IEnumerable<TSource>[] sources)
{
return sources.Combine ();
}
Would this work for you?
public static class Parallel
{
public static void ForEach<T>(IEnumerable<T>[] sources,
Action<T> action)
{
foreach (var enumerable in sources)
{
ThreadPool.QueueUserWorkItem(source => {
foreach (var item in (IEnumerable<T>)source)
action(item);
}, enumerable);
}
}
}
// sample usage:
static void Main()
{
string[] s1 = { "1", "2", "3" };
string[] s2 = { "4", "5", "6" };
IEnumerable<string>[] sources = { s1, s2 };
Parallel.ForEach(sources, s => Console.WriteLine(s));
Thread.Sleep(0); // allow background threads to work
}
For C# 2.0, you need to convert the lambda expressions above to delegates.
Note: This utility method uses background threads. You may want to modify it to use foreground threads, and probably you'll want to wait till all threads finish. If you do that, I suggest you create sources.Length - 1 threads, and use the current executing thread for the last (or first) source.
(I wish I could include waiting for threads to finish in my code, but I'm sorry that I don't know how to do that yet. I guess you should use a WaitHandle Thread.Join().)