0

I'm doing repeated work on a List<string> to build an instance of MyClass, but for simplicity's sake (there are a lot of regular expressions and IndexOf operations involved), I have to currently Trim each line after every operation:

static MyClass Populate (\List<str> strList)
{
    MyClass myClassInstance = new MyClass();
    Operation1(ref strList, myClassInstance);
    TrimAllLines(strList);
    Operation2(ref strList, myClassInstance);
    TrimAllLines(strList);
    //...
    return myClassInstance;
}

Is there a good way (preferably a drop-in replacement ) to make it so that every time I write to strList, each string within is automatically trimmed?

Things I've toyed with:

  • A wrapper of string that trims on implicit conversion. Would lose string Intellisense, and IEnumerables do not similarly convert implicitly.
  • Inheriting List<string> with indexer get { return base[index]; } set { base[index] = value.Trim(); }. The indexer is not overridable.
Arithmomaniac
  • 4,604
  • 3
  • 38
  • 58
  • 3
    Why are you passing `strList` as `ref`? `List` is already a reference type. Remember, `ref` refers to the *variable*, not to the *value*. – Eric Lippert Jul 05 '13 at 16:42
  • Eric Lippert: I know I don't have to; it's more of a reminder to myself that it's mutable, whereas strings are not. – Arithmomaniac Jul 05 '13 at 16:43
  • 9
    That is a very poor programming practice. Only pass `ref` when you need to *modify a variable*. – Eric Lippert Jul 05 '13 at 16:44

2 Answers2

13

Is there a good way (preferably a drop-in replacement ) to make it so that every time I write to strList, each string within is automatically trimmed?

You don't want the behavior of List<T>, so don't use List<T>. Instead, make your method take IList<T> and provide an implementation of that interface that does what you want.

The implementation might simply be a wrapper class that contains a private List<T>.

See also this related question:

How do I override List<T>'s Add method in C#?

Community
  • 1
  • 1
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
0

You could use

System.Collections.ObjectModel.ObservableCollection

instead of your List

And do something like:

    ObservableCollection<string> myCollection = new ObservableCollection<string>();

    void Init()
    {
        myCollection.CollectionChanged +=myCollection_CollectionChanged;
    }

    void myCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        myCollection.CollectionChanged -= myCollection_CollectionChanged;
        //could be a delete / clear / remove at operation
        if (e.NewItems != null)
        {
            for (int i = 0; i < e.NewItems.Count; i++)
            {
                string str = (string)e.NewItems[i];
                //the added value could be null
                if (str != null)
                {
                    string trimmed = str.Trim();                        
                    if (!trimmed.Equals(str))
                    {
                        myCollection[e.NewStartingIndex + i] = str.Trim();
                    }
                }
            }
        }
        myCollection.CollectionChanged += myCollection_CollectionChanged;
    }

after that, each time the ObservableCollection will be modified, the added items will be automatically trimmed.

br1
  • 313
  • 1
  • 10
  • 2
    Because of your `IndexOf()`, adding to the collection is now a O(n) operation. That could potentially slow down the code a lot. – svick Jul 05 '13 at 20:48
  • 1
    @svick makes an excellent point; this slows down the collection a lot potentially. I note that you could make it faster by first checking to see if `str == str.Trim()`. If it does then there is no need to do the expensive search. – Eric Lippert Jul 05 '13 at 22:10
  • 1
    There's no need for the `IndexOf()` call: you can reference `args.NewStartingIndex` to get the index of the first item; subsequent items will be contiguous from there. – dlev Jul 05 '13 at 23:13