This might be a loaded question, but here goes. I have some code that is very similar between all the methods. I am trying to find a way to accomplish all methods with a generic method/function. I'm not sure if I should be using delegates, and if so how to implement in this specific situation, or if there is a much more simple way to make a generic method.
Below I have copied the code I am trying to make generic. All methods take this basic syntax: (Parameters) ConcurrentQueue(pPeople), With that collection, the first part gets the count of the records. Each method iterates over a different part of the collection (or collection in the collection).
Thanks for any help or nudges in the right direction! If you have an idea that would help, it would be great if you could give an example related to this code (or very similar).
Code: I have copied three methods that give that show similar code (there are many more).
private void UpdatepPeopleAddressIDs(ConcurrentQueue<pPeople> people)
{
//Get Count of records that need an ID from uMaxIDs
int updateCount = 0; object lockObject = new object();
Parallel.ForEach<pPeople>(people, person =>
{
person.myPeopleAddressList.ForEach(address =>
{
if (address.ID == 0)
{
lock (lockObject)
{
updateCount++;
}
}
});
});
}
private void UpdatepPeopleContactNumbersIDs(ConcurrentQueue<pPeople> people)
{
//Get Count of records that need an ID from uMaxIDs
int updateCount = 0; object lockObject = new object();
Parallel.ForEach<pPeople>(people, person =>
{
person.myPeopleContactsList.ForEach(contact =>
{
if (contact.ID == 0)
{
lock (lockObject)
{
updateCount++;
}
}
});
});
}
private void UpdatepPeopleEmailIDs(ConcurrentQueue<pPeople> people)
{
//Get Count of records that need an ID from uMaxIDs
int updateCount = 0; object lockObject = new object();
Parallel.ForEach<pPeople>(people, person =>
{
person.myPeopleEmailsList.ForEach(emails =>
{
if (emails.ID == 0)
{
lock (lockObject)
{
updateCount++;
}
}
});
});
}
2 Answers 2
This is fairly easy to achieve. You need to make use of callback, which can perform the functionality specific to the method, which your generic method then uses. Something like this:
private void UpdatepPeople<T>(ConcurrentQueue<pPeople> people,
Func<PersonClass, List<T>> listProvider,
Func<T, bool> updateRequiredTest)
{
var updateCount = 0;
var lockObject = new object();
Parallel.ForEach<pPeople>(people, person =>
{
listProvider(person).ForEach(item =>
{
if (updateRequiredTest(item))
{
lock (lockObject)
{
updateCount++;
}
}
});
});
}
private void UpdatepPeopleContactNumbersIDs(ConcurrentQueue<pPeople> people)
{
UpdatepPeople<ContactType>(people,
person => person.myPeopleContactsList,
contact => contact.ID == 0);
}
private void UpdatepPeopleEmailIDs(ConcurrentQueue<pPeople> people)
{
UpdatepPeople<EmailType>(people,
person => person.myPeopleEmailsList,
contact => emails.ID == 0);
}
Here is an example of an update people function and a call to it.
I make no claim to your code being correct, I'm just refactoring to the generic case given the code you posted.
private void UpdatePeople(ConcurrentQueue<pPeople> people, Action<pPeople> actOn)
{
//Get Count of records that need an ID from uMaxIDs
int updateCount = 0; object lockObject = new object();
Parallel.ForEach<pPeople>(people, person => actOn(person));
}
private void UpdatepPeopleEmailIDs(ConcurrentQueue<pPeople> people)
{
UpdatePeople(people, person =>
{
person.myPeopleEmailsList.ForEach(emails =>
{
if (emails.ID == 0)
{
lock (lockObject)
{
updateCount++;
}
}
});
});
}
Interlocked.Increment
might be a viable option. But again: since this is just a trivial test and increment, I can't see the purpose of parallelism here \$\endgroup\$