Say I have the following methods in my code:
public bool RemoveItem(Item item)
{
// Logic to remove a single item
}
public bool RemoveItems(List<Item> items)
{
// Logic for removing multiple items. Running over all items and calling RemoveItem will be inefficient in my case
}
public bool AddItem(Item item)
{
// Logic for adding single item
}
public bool AddItems(List<Item> items)
{
// Logic for adding multiple items
}
Is there a way to prevent having multiple methods for each operation? I have alot of such methods. I wish to somehow combine each couple of methods into a single one..is there a nice way for doing so?
I can create a list with single item and support only methods that take list as parameter but is seems ugly to me.
How do other people do it?
You can create your methods with params keyword:
public bool AddItems(params Item[] items)
{
...
}
public bool RemoveItems(params Item[] items)
{
...
}
This allows you call these methods like this:
AddItems(item);
AddItems(item1, item2, ...);
or
AddItems(new Item[] { ... });
Your approach is right. This is the way it's implemented in the list class, where you have Add() and AddRange()
Better to get a list every time no matter if you have one or many items and handle in a single funstion.
Related
I know similar questions have been asked before, but I've come to a dead end while trying to find the best design pattern I can use.
I am trying to make a class-library with a factory class that provides enumerators for different items via method calls.
Note: Those items don't exist in a collection and can only be created knowing the previous one. (e.g. x(i) = x(i-1) + θ) Because of that I cannot implement those items as IEnumerable(s)
What I thought until now:
public static class AllItems {
public sealed class ItemsEnumerator: IEnumerator<Item>{
//those classes have non-public constructors
.....
}
public static ItemsEnumerator GetItemsEnumerator() {
return new ItemsEnumerator();
}
public sealed class OtherItemsEnumerator:IEnumerator<OtherItem>{
....
}
public static ItemsEnumerator GetOtherItemsEnumerator() {
return new ItemsOtherEnumerator();
}
}
this way i could do :
foreach(var item in AllItems.GetItemsEnumerator()){
//do something with item
}
which won't work, because according to c# spec ItemsEnumerator doesn't have a GetEnumerator function(To be used in a foreach statement)
If I change it to this
public static class AllItems {
public sealed class ItemsEnumerator: IEnumerator{
.....
public IEnumerator<Item> GetEnumerator() {
return this;
}
}
public static ItemsEnumerator GetItemsEnumerator() {
return new ItemsEnumerator();
}
}
Is this a good design in general, or am I missing something here?
EDIT: Clarification on c# spec limitation
I am trying to make a class-library with a factory class that provides enumerators for different items via method calls. Note: Those items don't exist in a collection and can only be created knowing the previous one. (e.g. x(i) = x(i-1) + θ) Because of that I cannot implement those items as IEnumerable(s)
You don't need to go to that level of detail - you can just use yield to achieve a "conceptual" collection without having to wire in all of the enumeration plumbing:
public IEnumerable<Item> GetItems()
{
int i = 0;
while(i < 100) // or foreach(Item item in _baseItems), etc.
{
Item item = new Item();
item.X = i;
i += 10;
yield return item;
}
}
Note that this is just for illustration to show one way of returning a "collection" of items that are generated on-the fly. You are free to adapt this to your situation in whatever way is appropriate.
Let's say I have a list in a class which will be used in a multi threading scenario.
public class MyClass
{
List<MyItem> _list= new List<MyItem>();
protected object SyncRoot {
get {
return ((IList)_list).SyncRoot;
}
}
public void Execute1()
{
lock(SyncRoot)
{
foreach(var item in _list) DoSomething(item);
}
}
public void Execute2()
{
Item[] list;
lock(SyncRoot)
{
list=_list.ToArray();
}
for(var i=0;i<list.Length;i++) DoSomething(list[i]);
}
}
The method Execute1 is the 'normal' way to enumerate the list in a thread-safe way. But what about Execute2? Is this approach still thread-safe?
Access to the (copy of the) List is threadsafe in both scenarios. But of course the MyItem elements are not synchronized in any way.
The second form looks a little more expensive but it will allow Add/Remove on the original while the DoSomething()s are running. The array acts like a kind of snapshot, if that matches your requirements it could be useful. Note that you might as well use ToList().
It's safe as long as every other use of _list is also protected with the same lock statement. You are taking exclusive access to the list, copying its contents and then working on the copy (to which you also have exclusive access due to scoping). A bit wasteful at first sight, but a legitimate approach under certain circumstances.
Is there a one line LINQ statement that would replace the foreach loop in the code below?
public static ReplaceItemsOnOrder(Order order, List<OrderItem> replacements)
{
order.Items.Clear();
foreach (var item in replacements)
{
order.Items.Add(item);
}
}
EDIT:
Here is a simplified definition for the Order class:
public class Order
{
private Collection<OrderItem> _items = new Collection<OrderItem>();
public Collection<OrderItem> Items
{
get { return _items; }
}
}
You could write the following:
order.Items.Clear();
replacements.ForEach(order.Items.Add);
Alternatively if there's an addRange method (available on List<T>):
order.Items.Clear();
order.Items.AddRange(replacements);
It's not LINQ but there's AddRange
order.Items.AddRange(replacements);
But you haven't said what Items is, so unless it's a List that method won't be available.
No, Linq is about selecting, not modifying.
You could write your own extension method to add this feature though.
Is order.Items a List? You could have:
public static ReplaceItemsOnOrder(Order order, List<OrderItem> replacements)
{
order.Items = new List<OrderItem>(replacements);
}
This makes sense because, in your example code, it seems you're replacing the items in order.Items. List<T> has a constructor which accepts an IEnumerable<T> argument, whose contents will be copied to the list being constructed.
It's also safer in the sense that if an error occurrs at construction time (including the copy operation), it won't result in a half-full new list.
I have List with objects of strings and doubles, and I try to call different methods based on the itemtype and their value. In the debugger I can see that the first iteration works fine, but an error shows when entering the second time after a method is called.
If i comment out the methods and put in simple methods it works, so I understand that it something with how I call the methods.
What do I do wrong, and what can I do to make it work?
If there is easier ways to do what I'm trying, please let me know.
public double evaluateExpressionUsingVariableValues(List<Object> anExpression, Dictionary<String, double> variables)
{
foreach (object element in anExpression)
{
if(element.GetType()!=typeof(string))
{
setOperand((double)element);
}
else if (element.GetType() == typeof(string))
{
if (!element.ToString().StartsWith("%"))
performOperation((string)element);
else
setOperand(variables[element.ToString()]);
}
}
return this.operand;
}
If your methods (setOperand, performOperation) modify the collection at all, you will get an exception. You can't modify the collection while you are iterating over it. One method is to create a result collection and add items to it as you change them, rather than trying to modify the collection in-place.
private void Foo() {
foreach(var item in items) {
if (item.IsBad) {
DeleteItem(item); // will throw an exception as it tries to modify items
}
}
}
private void DeleteItem(Item item) {
items.Remove(item);
}
Instead, try:
private void Foo() {
List<Item> result = new List<Item>();
foreach(var item in items) {
if (!item.IsBad) {
result.Add(item); // we are adding to a collection other
// than the one we are iterating through
}
}
items = result; // we are no longer iterating, so we can modify
// this collection
}
Are you sure that none of the methods you are calling is modifying the collection (anExpression) ? This kind of problem is often the result of that. Try replacing the foreach by a for loop and see if you still get the same issue.
I'm writing a class to represent a Pivot Collection, the root object recognized by Pivot. A Collection has several attributes, a list of facet categories (each represented by a FacetCategory object) and a list of items (each represented by a PivotItem object). Therefore, an extremely simplified Collection reads:
public class PivotCollection
{
private List<FacetCategory> categories;
private List<PivotItem> items;
// other attributes
}
What I'm unsure of is how to properly grant access to those two lists. Because declaration order of both facet categories and items is visible to the user, I can't use sets, but the class also shouldn't allow duplicate categories or items. Furthermore, I'd like to make the Collection object as easy to use as possible. So my choices are:
Have PivotCollection implement IList<PivotItem> and have accessor methods for FacetCategory: In this case, one would add an item to Collection foo by writing foo.Add(bar). This works, but since a Collection is equally both kinds of list making it only pass as a list for one type (category or item) seems like a subpar solution.
Create nested wrapper classes for List (CategoryList and ItemList). This has the advantage of making a consistent interface but the downside is that these properties would no longer be able to serve as lists (because I need to override the non-virtual Add method I have to implement IList rather than subclass List. Implicit casting wouldn't work because that would return the Add method to its normal behavior.
Also, for reasons I can't figure out, IList is missing an AddRange method...
public class PivotCollection
{
private class CategoryList: IList<FacetCategory>
{
// ...
}
private readonly CategoryList categories = new CategoryList();
private readonly ItemList items = new ItemList();
public CategoryList FacetCategories
{
get { return categories; }
set { categories.Clear(); categories.AddRange(value); }
}
public ItemList Items
{
get { return items; }
set { items.Clear(); items.AddRange(value); }
}
}
Finally, the third option is to combine options one and two, so that PivotCollection implements IList<PivotItem> and has a property FacetCategories.
Question: Which of these three is most appropriate, and why?
The best thing to do here is to create your own collection class that inherits System.Collections.ObjectModel.Collection<T> and overrides InsertItem.