Is the following thread safe? - c#

I have the following code and wonder whether it is thread safe. I only lock when I add or remove items from the collection but do not lock when I iterate over the collection. Locking while iterating would severely impact performance because the collection potentially contains hundreds of thousands of items. Any advice what to do to make this thread safe?
Thanks
public class Item
{
public string DataPoint { get; private set; }
public Item(string dataPoint)
{
DataPoint = dataPoint;
}
}
public class Test
{
private List<Item> _items;
private readonly object myListLock = new object();
public Test()
{
_items = new List<Item>();
}
public void Subscribe(Item item)
{
lock (myListLock)
{
if (!_items.Contains(item))
{
_items.Add(item);
}
}
}
public void Unsubscribe(Item item)
{
lock (myListLock)
{
if (_items.Contains(item))
{
_items.Remove(item);
}
}
}
public void Iterate()
{
foreach (var item in _items)
{
var dp = item.DataPoint;
}
}
}
EDIT
I was curious and again profiled performance between an iteration that is not locked vs iterating inside the lock on the myListLock and the performance overhead of locking the iteration over 10 million items was actually quite minimal.

No, it isn't thread safe, because the collection could be modified while you look inside it... What you could do:
Item[] items;
lock (myListLock)
{
items = _items.ToArray();
}
foreach (var item in items)
{
var dp = item.DataPoint;
}
so you duplicate the collection inside a lock before cycling on it. This clearly will use memory (because you have to duplicate the List<>) (ConcurrentBag<>.GetEnumerator() does nearly exactly this)
Note that this works only if Item is thread safe (for example because it is immutable)

In theory your code is not threadsafe.
In the background foreachperforms a normal for loop and if you add an item from a distinct thread while foreachiterates through your list, an item might be left out. Also if you remove an item (from a distinct thread), you might get an AV exception or - even worse - gibberish data.
If you want your code to be threadsafe, you have two choices:
You can clone your list (I usually use the .ToArray() method for that purpose). It will lead to doubling the list in the memory with all its cost and the result might not be up-to-date for in-situ editions, or...
You can put your entire iteration in a locked block, which will result in blocking other threads accessing the array while you are performing a long-running operation.

No it isn't. Note that all classes documented on MSDN has a section on Thread Safety (near the end): https://msdn.microsoft.com/en-us/library/6sh2ey19%28v=vs.110%29.aspx
The documentation for GetEnumerator has some more notes: https://msdn.microsoft.com/en-us/library/b0yss765%28v=vs.110%29.aspx
The key point is that iteration is not itself thread-safe. Even if each individual iterated read from the collection is thread safe, a consistent iteration often breaks down if the collection is modified. You could get problems such as reading the same element twice or skipping some elements, even if the collection itself is never in an inconsistent state.
Btw, your Unsubscribe() is doing TWO linear searches of the list, which is probably not what you want. You shouldn't need to call Contains() before Remove().

Related

Why is hashset.exceptwith twice as fast iterating and checking !contains on the other collection?

I was just doing a bit of optimizations and was baffled by this.
My original code looked something like this:
HashSet<IExampleAble> alreadyProcessed;//a few million items
void someSetRoutineSlower(HashSet<IExampleAble> exampleSet)
{
foreach (var item in exampleSet)
{
if (!alreadyProcessed.Contains(item))
{
// do Stuff
}
}
}
This took about 1.2million ticks to process.
Then I tried the same with exceptwith:
void someSetRoutineFaster(HashSet<IExampleAble> exampleSet)
{
exampleSet.ExceptWith(alreadyProcessed);//doesnt this have to check each item of it's collection against the other one, thus actually looping twice?
foreach (var item in exampleSet)
{
// do Stuff
}
}
and it was running running at about 0.4mil-0.7mil ticks.
What kind of optimization is going on in exceptwith? Doesn't it also have to do a check over all items as I do in the first code-snippet?
According to Reference Source for HashSet ExceptWith method in .NET Framework 4.7.2 looks like this:
public void ExceptWith(IEnumerable<T> other) {
if (other == null) {
throw new ArgumentNullException("other");
}
Contract.EndContractBlock();
// this is already the enpty set; return
if (m_count == 0) {
return;
}
// special case if other is this; a set minus itself is the empty set
if (other == this) {
Clear();
return;
}
// remove every element in other from this
foreach (T element in other) {
Remove(element);
}
}
Only explicit optimizations in the method are for the special cases when a set is empty or "excepted" with itself.
Speed up you are experiencing probably comes from the difference between calling Contains(T) and iterating over all elements when the number of Contains(T) calls is comparable to the set size. On the face of it, it seems it should perform the same, old implementation called Contains(T) explicitly, new implementation performs the same kind of search in Remove(T). The difference is as the elements are being removed the set its internal structure becomes more sparse. This results in a statistically less items (slots as per source code notation) per bucket and finding an element becomes faster, if present then it's the first item in the bucket.
It all depends on the quality of hashing function for your objects. Ideally each object should be alone in it's bucket but most real hash functions would distribute million elements with collisions (multiple elements in the same bucket).

Is there any performance hit to setting a list as itself?

I have a list that may be null if not yet instantiated, and I want when calling GetList() to be able to return existing or create the list and then return. This looks cleaner:
private List<object> m_objects;
public List<object> GetList()
{
m_objects = m_objects ?? new List<object>();
return m_objects;
}
But is there a performance hit for setting the list as itself, or does C# realize that that's not necessary?
The alternative would be:
private List<object> m_objects;
public List<object> GetList()
{
if(m_objects != null)
{
return m_objects;
}
m_objects = new List<object>();
return m_objects;
}
Obviously not the end of the world but I'm still curious.
Use Lazy<T>:
private Lazy<List<object>> m_objects = new Lazy<List<object>>();
public List<object> GetList()
{
return m_objects.Value;
}
Addressing the performance issue. Worrying about performance here is premature optimisation. You should code it first to just work and then if you see any performance related problems, profile it and optimise.
This is perfectly valid:
private List<string> items;
public List<string> Items { get { return items ?? (items = new List<string>()); } }
note the ?? (items = difference. There is no performance hit as it is boolean short circuited at ?? if it has a non null value.
As pointed out, in case you want to use your code, then YES, it does pose performance hit as new element is created each time.
As the question specifically asks for performance, this gives you the best possible performance when calling GetList() and it's thread safe:
private readonly List<object> m_objects = new List<object>();
public List<object> GetList()
{
return m_objects;
}
Another option for making it thread safe would be using Lazy<T>. This defers the new List<object>() at the expense of always doing new Lazy<List<object>>() with additional overhead in the GetList() method.
There will probably be a minimal performance hit because you are basically assigning the reference held in m_objects to the m_objects field. That is effectively just copying a 64 or 32-bit pointer. You wouldn't be copying around all the data, just the reference to the instance of the object (or null).
For your code, I think using the ?? quotations is very neat and adequate as long as you aren't worried about multiple threading. If you are, then the Lazy<> suggest that #Michał Kędrzyński suggested is the better way to go since you wouldn't need to program all that in.
The only exception being if that you needed to make sure you were on the Dispatcher thread in WPF or the UI thread in Winforms due to UI limitations.
Edit
Just to correct my own answer, using Lazy is moot if your generic type isn't thread-safety aware anyway (for example, List isn't thread safe)

How to write copy-on-write list in .NET

How to write a thread-safe list using copy-on-write model in .NET?
Below is my current implementation, but after lots of reading about threading, memory barriers, etc, I know that I need to be cautious when multi-threading without locks is involved. Could someone comment if this is the correct implementation?
class CopyOnWriteList
{
private List<string> list = new List<string>();
private object listLock = new object();
public void Add(string item)
{
lock (listLock)
{
list = new List<string>(list) { item };
}
}
public void Remove(string item)
{
lock (listLock)
{
var tmpList = new List<string>(list);
tmpList.Remove(item);
list = tmpList;
}
}
public bool Contains(string item)
{
return list.Contains(item);
}
public string Get(int index)
{
return list[index];
}
}
EDIT
To be more specific: is above code thread safe, or should I add something more? Also, will all thread eventually see change in list reference? Or maybe I should add volatile keyword on list field or Thread.MemoryBarrier in Contains method between accessing reference and calling method on it?
Here is for example Java implementation, looks like my above code, but is such approach also thread-safe in .NET?
And here is the same question, but also in Java.
Here is another question related to this one.
Implementation is correct because reference assignment is atomic in accordance to Atomicity of variable references. I would add volatile to list.
Your approach looks correct, but I'd recommend using a string[] rather than a List<string> to hold your data. When you're adding an item, you know exactly how many items are going to be in the resulting collection, so you can create a new array of exactly the size required. When removing an item, you can grab a copy of the list reference and search it for your item before making a copy; if it turns out that the item doesn't exist, there's no need to remove it. If it does exist, you can create a new array of the exact required size, and copy to the new array all the items preceding or following the item to be removed.
Another thing you might want to consider would be to use a int[1] as your lock flag, and use a pattern something like:
static string[] withAddedItem(string[] oldList, string dat)
{
string[] result = new string[oldList.Length+1];
Array.Copy(oldList, result, oldList.Length);
return result;
}
int Add(string dat) // Returns index of newly-added item
{
string[] oldList, newList;
if (listLock[0] == 0)
{
oldList = list;
newList = withAddedItem(oldList, dat);
if (System.Threading.Interlocked.CompareExchange(list, newList, oldList) == oldList)
return newList.Length;
}
System.Threading.Interlocked.Increment(listLock[0]);
lock (listLock)
{
do
{
oldList = list;
newList = withAddedItem(oldList, dat);
} while (System.Threading.Interlocked.CompareExchange(list, newList, oldList) != oldList);
}
System.Threading.Interlocked.Decrement(listLock[0]);
return newList.Length;
}
If there is no write contention, the CompareExchange will succeed without having to acquire a lock. If there is write contention, writes will be serialized by the lock. Note that the lock here is neither necessary nor sufficient to ensure correctness. Its purpose is to avoid thrashing in the event of write contention. It is possible that thread #1 might get past its first "if" test, and get task task-switched out while many other threads simultaneously try to write the list and start using the lock. If that occurs, thread #1 might then "surprise" the thread in the lock by performing its own CompareExchange. Such an action would result in the lock-holding thread having to waste time making a new array, but that situation should arise rarely enough that the occasional cost of an extra array copy shouldn't matter.
Yes, it is thread-safe:
Collection modifications in Add and Remove are done on separate collections, so it avoids concurrent access to the same collection from Add and Remove or from Add/Remove and Contains/Get.
Assignment of the new collection is done inside lock, which is just pair of Monitor.Enter and Monitor.Exit, which both do a full memory barrier as noted here, which means that after the lock all threads should observe the new value of list field.

Can't add/remove items from a collection while foreach is iterating over it

If I make my own implementation of IEnumerator interface, then I am able ( inside foreach statement )to add or remove items from a albumsList without generating an exception.But if foreach statement uses IEnumerator supplied by albumsList, then trying to add/delete ( inside the foreach )items from albumsList will result in exception:
class Program
{
static void Main(string[] args)
{
string[] rockAlbums = { "rock", "roll", "rain dogs" };
ArrayList albumsList = new ArrayList(rockAlbums);
AlbumsCollection ac = new AlbumsCollection(albumsList);
foreach (string item in ac)
{
Console.WriteLine(item);
albumsList.Remove(item); //works
}
foreach (string item in albumsList)
{
albumsList.Remove(item); //exception
}
}
class MyEnumerator : IEnumerator
{
ArrayList table;
int _current = -1;
public Object Current
{
get
{
return table[_current];
}
}
public bool MoveNext()
{
if (_current + 1 < table.Count)
{
_current++;
return true;
}
else
return false;
}
public void Reset()
{
_current = -1;
}
public MyEnumerator(ArrayList albums)
{
this.table = albums;
}
}
class AlbumsCollection : IEnumerable
{
public ArrayList albums;
public IEnumerator GetEnumerator()
{
return new MyEnumerator(this.albums);
}
public AlbumsCollection(ArrayList albums)
{
this.albums = albums;
}
}
}
a) I assume code that throws exception ( when using IEnumerator implementation A supplied by albumsList ) is located inside A?
b) If I want to be able to add/remove items from a collection ( while foreach is iterating over it), will I always need to provide my own implementation of IEnumerator interface, or can albumsList be set to allow adding/removing items?
thank you
Easiest way is to either reverse through the items like for(int i = items.Count-1; i >=0; i--), or loop once, gather all the items to remove in a list, then loop through the items to remove, removing them from the original list.
Generally it's discouraged to design collection classes that allow you to modify the collection while enumerating, unless your intention is to design something thread-safe specifically so that this is possible (e.g., adding from one thread while enumerating from another).
The reasons are myriad. Here's one.
Your MyEnumerator class works by incrementing an internal counter. Its Current property exposes the value at the given index in an ArrayList. What this means is that enumerating over the collection and removing "each" item will actually not work as expected (i.e., it won't remove every item in the list).
Consider this possibility:
The code you posted will actually do this:
You start by incrementing your index to 0, which gives you a Current of "rock." You remove "rock."
Now the collection has ["roll", "rain dogs"] and you increment your index to 1, making Current equal to "rain dogs" (NOT "roll"). Next, you remove "rain dogs."
Now the collection has ["roll"], and you increment your index to 2 (which is > Count); so your enumerator thinks it's finished.
There are other reasons this is a problematic implementation, though. For instance someone using your code might not understand how your enumerator works (nor should they -- the implementation should really not matter), and therefore not realize that the cost of calling Remove within a foreach block incurs the penalty of IndexOf -- i.e., a linear search -- on every iteration (see the MSDN documentation on ArrayList.Remove to verify this).
Basically, what I'm getting at is: you don't want to be able to remove items from within a foreach loop (again, unless you're designing something thread-safe... maybe).
OK, so what is the alternative? Here are a few points to get you started:
Don't design your collection to allow -- let alone expect -- modification within an enumeration. It leads to curious behavior such as the example I provided above.
Instead, if you want to provide bulk removal capabilities, consider methods such as Clear (to remove all items) or RemoveAll (to remove items matching a specified filter).
These bulk-removal methods can be implemented fairly easily. ArrayList already has a Clear method, as do most of the collection classes you might use in .NET. Otherwise, if your internal collection is indexed, a common method to remove multiple items is by enumerating from the top index using a for loop and calling RemoveAt on indices where removal is desired (notice this fixes two problems at once: by going backwards from the top, you ensure accessing each item in the collection; moreover, by using RemoveAt instead of Remove, you avoid the penalty of repeated linear searches).
As an added note, I would strongly encourage steering clear of non-generic collections such as ArrayList to begin with. Go with strongly typed, generic counterparts such as List(Of Album) instead (assuming you had an Album class -- otherwise, List(Of String) is still more typesafe than ArrayList).
Suppose I have a collection, an array for that matter
int[] a = { 1, 2, 3, 4, 5 };
I have a function
public IList<int> myiterator()
{
List<int> lst = new List<int>();
for (int i = 0; i <= 4; i++)
{
lst.Add(a[i]);
}
return lst;
}
Now i call this function and iterate over and try to add
var a = myiterator1();
foreach (var a1 in a)
{
a.Add(29);
}
Will cause a runtime exception
Here thing to notice is that if we are allowed to add for each element
in list
list will become something like {1,2,3,4,5,6}
then for every element and every newly added we keep on adding coz of that
we will be stuck in a infinite operation as it will again be repeated for every element
From the MSDN documentation for INotifyCollectionChanged:
You can enumerate over any collection
that implements the IEnumerable
interface. However, to set up dynamic
bindings so that insertions or
deletions in the collection update the
UI automatically, the collection must
implement the INotifyCollectionChanged
interface. This interface exposes the
CollectionChanged event that must be
raised whenever the underlying
collection changes.
WPF provides the
ObservableCollection<(Of <(T>)>)
class, which is a built-in
implementation of a data collection
that exposes the
INotifyCollectionChanged interface.
For an example, see How to: Create and
Bind to an ObservableCollection.
The individual data objects within the
collection must satisfy the
requirements described in the Binding
Sources Overview.
Before implementing your own
collection, consider using
ObservableCollection<(Of <(T>)>) or
one of the existing collection
classes, such as List<(Of <(T>)>),
Collection<(Of <(T>)>), and
BindingList<(Of <(T>)>), among many
others.
If you have an advanced scenario and
want to implement your own collection,
consider using IList, which provides a
non-generic collection of objects that
can be individually accessed by index
and provides the best performance.
Sounds to me that the problem is in the Collection itself, and not its Enumerator.

To Save a loop or to go with 2 methods - Convention vs. Performance

So everyone who cares about best practices in OOP and keeping code clean and in OOP knows that methods shouldn't be doing more than one thing. Methods are discrete units that do one thing and get out.
But here's a situation though where you could save some processing and improve performance if you were to combine 2 methods which are really doing 2 things into one and reuse the existing for loop that you already have in the first method:
private void RemoveDiscontinuedItems()
{
for(int s = 0; s < itemList.Count; s++)
{
if(!itemList[s].ItemIsOnSite)
{
RemoveItem(itemList[s].Id); // remove it from the DB
itemList.RemoveAt(s); // remove it from the collection
s--;
}
}
}
private void RemovePriceChangedItems()
{
for (int s = 0; s < itemList.Count; s++)
{
if(!PricingOptionIsValid(itemList[s]))
{
RemoveItem(itemList[s].Id); // remove it from the DB
itemList.RemoveAt(s); // remove it from the collection
s--;
}
}
}
These are called at page load. One removes items that are discontinued. The other removes items that have some pricing options that have changed and removes them from the same list.
Now if we were to stick with best practices, one could say that these are 2 completely independent purposes, thus we should not combine the logic in both these methods. That would then make the method be doing 2 things and I'd also have to come up with some f'd up name like RemoveDiscontinuedAndPriceChangeItems() or a generic name that doesn't tell me jack sh** like RemoveInvalidItemsFromList():
private void RemoveDiscontinuedItems()
{
for(int s = 0; s < itemsList.Count; s++)
{
if((!itemList[s].ItemIsOnSite))
{
RemoveItem(orderItemsSavedList[s].Id); // remove it from the DB
itemList.RemoveAt(s); // remove it from the collection
s--;
}
else if(!PricingOptionIsValid(itemList[s]))
{
RemoveItem(itemList[s].Id); // remove it from the DB
itemList.RemoveAt(s); // remove it from the collection
s--;
}
}
however thinking about the performance side, calling 2 methods that are looping through the same list to remove some items, would be more costly in cycles.
So, anyone against combining or are you for combining in this situation? Would like to hear some opinions out there.
Why not refactor so that each method performs a single action, rather then doing the loop. Then in the body of the loop call each method as needed.
Update
Here is a quick example based on your methods. Obviously the Loop method would be something different, in you application, however, I didn't have any other context for what you were doing. Also, I changed your for loop to a foreach.
private void Loop()
{
foreach (Item i in itemList)
{
if(!item.ItemIsOnSite)
{
RemoveDiscontinuedItems(i)
}
if(!item.PricingOptionIsValid)
{
RemovePriceChangedItems(i)
}
}
}
private void RemoveDiscontinuedItems(itemType item)
{
RemoveItem(item.Id); // remove it from the DB
item.Remove; // remove it from the collection
}
private void RemovePriceChangedItems(itemType item)
{
RemoveItem(item.Id); // remove it from the DB
item.Remove; // remove it from the collection
}
I think you're factoring is in the wrong place.
If you wrote it like this:
public void ConditionallyRemoveItems(Func<Item,bool> predicate)
{
for (int s=0; s < itemsList.Count; s++) {
if (predicate(itemList[s])) {
RemoveItem(orderItemsSavedList[s].Id);
itemList.RemoveAt(s);
s--;
}
}
}
// ...
ConditionallyRemoveItems(i => !i.ItemIsOnSize || !PricingOptionIsValid(i));
I also don't really like your style of messing with the loop variable - I prefer this style:
List<Item> itemsToRemove = new List<Items>();
foreach (Item i in itemList) {
if (predicate(i)) {
itemsToRemove.Add(i);
}
}
foreach (Item i in itemsToRemove)
itemList.Remove(i);
and if you don't like the performance of that, you can always do this:
List<Item> itemsToKeep = new List<Items>();
foreach (Item i in itemList) {
if (!predicate(i)) {
itemsToKeep.Add(i);
}
}
itemList = itemsToKeep;
A few things:
I don't see why you are looping forward when removing the items. You should be looping backwards and avoid the messy index manipulation when you perform a removal.
Thinking of this in terms of removing one item vs another based on an attribute is incorrect. You should see it as filtering the list. To that end, you should have a method that takes a Predicate<T> and then returns an IEnumerable<T> which you can then enumerate though (or an IList<T>, the same, if you want to just mutate the list). This way, you have the operation of filtering the list and the conditions separate (which is better separation IMO).
If you have access to LINQ, then there really is no reason to do this. You should be using a where filter on the original list, and if you want, factoring out the filtering logic into separate methods which will take the item and see if it should be returned. You can then construct your where clause (or Predicate<T> to pass to the Where extension method) from that.
this is probably the simplest way to do it, using a loop:
//counting backwards is easier when you are doing removals from a list
for( int i = lst.Count -1; i>= 0; i--)
{
if(condition1 || condition2)
{
RemoveFromDB(lst[i]);
lst.RemoveAt(i);
}
}
you can refactor that to use the functional methods provided by the framework:
var toRemove = lst.FindAll(
item => !PricingOptionIsValid(item) || !item.ItemIsOnSite()
);
toRemove.ForEach( item =>
{
RemoveFromDB(item.ID);
lst.Remove(item);
});
and you could write this without the toRemove variable, by chaining the ForEach onto the FindAll
There are several good suggestions on how to simplify and clarify your current code.
When considering performance always start with clean and concise code, don't worry about optimization until you have PROVEN a need to optimize.
Almost everything anyone writes in a high-level language:
a) COULD be faster.
b) is fast ENOUGH.
Seems like the standard approach if possible would be to make a function out of the loop contents, and a function that does both things:
doBothThings()
{
for(sharedLoop)
{
function1(loop counter);
function2(loop counter);
}
}
Gives you the performance but still separates the two pieces of functionality into separate functions. Obviously, not so simple if the two functions involve code before/after the loop.
Since both of your methods are removing items from your list, it doesn't necessarily make sense to combine the loops. You should determine if there's a significant performance difference between the two methods that you're using.
For example, if PricingOptionIsValid is an expensive operation (hits the database or whatever), you would want to call that in a second loop, after you've pruned as many items as possible with the first loop.
If the order of the tests doesn't matter, you should place the more likely branch first, and the less likely branch second. If ItemIsOnSite is false only 1% of the time, you're going to spend a lot of cycles skipping it.
You also might consider using an iterator instead of manipulating your loop variable. Either that or just find items to remove in the loop, then do another loop to remove them all.
In C# I would almost certainly not repeat the removal logic at all. Consider something like:
private delegate bool RemovalExpression(ItemType item);
private void RemoveItems(RemovalExpression shouldRemove)
{
for (int s = 0; s < itemList.Count; s++)
{
if (shouldRemove(itemList[s]))
{
RemoveItem(itemList[s].Id);
itemList.RemoveAt(s);
s--;
}
}
}
Which can be naturally used as:
RemoveItems(item => !item.ItemIsOnSite);
RemoveItems(item => !PricingOptionIsValid(item));
RemoveItems(item => (!item.ItemIsOnSite || !PricingOptionIsValid(item)));
etc.
Also from the sounds of it, you shouldn't be worrying about looping micro-optimizations at this point. If you don't have data that explicitly indicates that you're spending a disproportionate amount of your time in item removal, you have no way of knowing which construct will be "faster", nor any objective way of knowing whether your choice was worth the time investment, or a needless complication, or an outright pessimization of performance.
Therefore, write for maintainability; simple and clear and with no repetition of logic.
Use LINQ. And, aren't we past the 15 char min limit?
Do whatever makes sense, reduces complexity, and is easiest to maintain. Best practices are a guide.
Well if we're talking about proper OO, it's probably not a good idea put the responsibility of keeping itemList and whatever RemoveItem does in sync on the caller.
Personally I would use a list which has an OnRemove event you can hook into, and add RemoveItem as the event. This removes the need for the caller to remember to call RemoveItem.
This then makes the code much simpler, allowing you to use something like:
private void RemoveDiscontinuedItems()
{
itemList.RemoveAll(x => !x.ItemIsOnSite);
}
private void RemovePriceChangedItems()
{
itemList.RemoveAll(x => !PricingOptionIsValid(x));
}
The code is cleaner and the logic and purpose more obvious.
The performance obviously needn't be a concern unless it becomes a problem, though you must remember to test with extreme values (in this case a large list).
If you find that iterating through the list multiple times is actually a bottleneck then I'd propose something like this:
private bool IsDiscontinuedItem(Item item)
{
return !item.ItemIsOnSite;
}
private bool IsPriceChangedItem(Item item)
{
return !PricingOptionIsValid(item);
}
private bool IsInvalidItem(Item item)
{
return IsDiscontinuedItem(item) ||
IsPriceChangedItem(item);
}
private void RemoveInvalidItems()
{
itemList.RemoveAll(IsInvalidItem)
}
Here's my version:
private void RemoveDiscontinuedItems()
{
RemoveItems(item => item.ItemIsOnSite);
}
private void RemovePriceChangedItems()
{
RemoveItems(item => PricingOptionIsValid(item));
}
private void RemoveAll()
{
RemoveItems(item => item.ItemIsOnSite || PricingOptionIsValid(item));
}
private void RemoveItems(Predicate<Item> removeIfTruePredicate)
{
itemList.RemoveAll(
item =>
{
if(removeIfTruePredicate(item))
{
RemoveItem(item);
return true;
}
return false;
});
}
Note, this is based on your use of a mutable list. I'd be tempted to consider whether a mutable list is really needed. If not, I'd prefer to use a more functional style, and use a linq where clause to create a new list that excludes the items which need removing.
Given your desire for performance though, my guess is that RemoveAll (I'm assuming you're using List<T>) will be quicker than creation of a new list. Of course you'd really need to check this to be sure.

Categories