10

I'm handling an event which passes event args pointing to a List and a T newitem, and my job is to add the newitem to the List.

How can I do this without checking for all the types I know T might be?

The current code is a couple dozen lines of this:

private void DataGridCollectionViewSource_CommittingNewItem(object sender, DataGridCommittingNewItemEventArgs e)
{
  Type t = e.CollectionView.SourceCollection.GetType();

  if (t == typeof(List<Person>))
  {
    List<Person> source = e.CollectionView.SourceCollection as List<Person>;
    source.Add(e.Item as Person);
  }
  else if (t == typeof(List<Place>))
  {
    List<Place> source = e.CollectionView.SourceCollection as List<Place>;
    source.Add(e.Item as Place);
  }
  ...

I'd prefer if it were possible to do something like this:

((List<T>) e.CollectionView.SourceCollection).Add((T)e.Item);

Any ideas?

Alain
  • 26,663
  • 20
  • 114
  • 184

4 Answers4

16

Simply don't use generics here:

IList source = (IList)e.CollectionView.SourceCollection;
source.Add(e.Item);

You could also use ICollection in place of IList.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 'System.Collections.ICollection' does not contain a definition for 'Add' - which is why I posted this initially, but I hadn't tried IList, that one works. Thanks. – Alain Feb 27 '12 at 16:09
  • @Alain ah, fair enough - I lost track of which methods are in which interface (iirc it is slightly different between the non-generic and generic versions) – Marc Gravell Feb 27 '12 at 16:10
  • As a sanity check, is there a way that I can verify that the SourceCollection is of the same type as e.Item? – Alain Feb 27 '12 at 16:11
  • @Alain only by using reflection. However, any list-of-T etc will throw an exception if it is wrong, which is easy to spot – Marc Gravell Feb 27 '12 at 16:15
  • 2
    @Alain you could test whether the source collection implements the generic `IList<>`, and, if it does, get the type argument, and then check whether `typeArg.IsAssignableFrom(e.Item.GetType())`. Note that this is a better approach than checking type equality, because, of course, `e.Item` might be an `Antelope` while the collection might implement `IList`. – phoog Feb 27 '12 at 16:19
  • @phoog that's fine, but would work best from a generic method. In a non-generic method tht is adding an awful lot of code just to reproduce wht already exists in all standrd generic collection implementations for free (I.e. type-checking when using the non-generic API). As a general rule, if you find yourself using masses of reflection in a generic method, it is worth looking for a on-generic implementation – Marc Gravell Feb 27 '12 at 16:45
  • @MarcGravell agreed. Checking the types with reflection would be overkill here, unless the OP has some course of action in mind *other than throwing an exception.* If an exception would be the proper response to incompatibility, however, especially since the object that owns both the `CollectionView` and the `Item` presumably guarantees that they're compatible, it makes more sense just to let the non-generic `IList.Add(object)` method throw the exception. – phoog Feb 27 '12 at 17:21
4

Since generic collections implement object-based interfaces defined in the System.Collections namespace, you can do this:

((System.Collections.IList) e.CollectionView.SourceCollection).Add(e.Item);

Of course the type checking is now shifted to runtime, so you need to make sure that e.Item would be of the correct type, because the compiler cannot check it after the cast.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

You could make a specific typed class?

public class MyClass<ABC>
    {
        private void DataGridCollectionViewSource_CommittingNewItem(
              object sender, DataGridCommittingNewItemEventArgs e)
        {
            Type t = e.CollectionView.SourceCollection.GetType();

        if (t == typeof(List<ABC>))
        {
            List<ABC> source = e.CollectionView.SourceCollection as List<ABC>;
            source.Add(e.Item as ABC);
        }
    }
}

or not depending on the context of what your trying to do....

AnthonyLambert
  • 8,768
  • 4
  • 37
  • 72
1
void AddItem<T>(IEnumerable sourceCollection, object item)
{
     ((List<T>)sourceCollectio).Add((T)item); 
}

Then

Type t = e.CollectionView.SourceCollection.GetType(); 
if (t == typeof(List<Person>)) { 
    AddItem<Person>(e.CollectionView.SourceCollection, e.Item);
} else if (t == typeof(List<Place>)) { 
    AddItem<Place>(e.CollectionView.SourceCollection, e.Item);
} 
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188