Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backdooring Generic Lists through IList

Tags:

c#

generics

ilist

I have a scenario where a class loads objects of one type, due do abstractions I can not use a generic class (generics tend to spread like cancer :) but I often want to work with a generic version of the objects once retrieved, which resulted in code like this (simplified):

List<SomeClass> items = Storage.LoadItems(filename).OfType<SomeClass>().ToList();

Where LoadItems returns a List<object>, then I realized, why not instead have

public void LoadItems(string filename,IList list);

Now I can do this instead

List<SomeClass> items = new  List<SomeClass>();
LoadItems(filename,items);

Which should be more efficient. It's also seems a bit more flexible since I can take an existing List and tack on new items. So my questions are, is this a common pattern or do you have a different/better way of achieving this?

I'm also a bit curious that you can do this, if you try and add a object of the wrong type you get an exception, but does that mean that generic lists also do a type check? (which seems a bit unecessary)

EDIT It might actually be a bit more elegant to modify the pattern to

public IList LoadItems(string filename,IList list=null);

that way you can use the statement fluently and if no list is passed you could simply instantiate a List<object>

like image 861
Homde Avatar asked Nov 12 '10 13:11

Homde


2 Answers

List<T> implements IList explicitly. The implementations cast to T and call the regular (generic) methods.

Thus, type-checking only happens if you explicitly call the IList methods. For example:

void System.Collections.IList.Insert(int index, Object item) 
{
    ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item); 

    try {
        Insert(index, (T) item); 
    }
    catch (InvalidCastException) {
        ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T));
    } 
}

It doesn't use the as keyword because the T might be a value type.
You can only write as T if you wrote where T : class.

like image 148
SLaks Avatar answered Oct 10 '22 04:10

SLaks


Using IList is fine in most cases; and is certainly faster than using reflection or dynamic to achieve the same.

Yes it will add a type-check (by virtue of the cast/unbox), but that will not be onerous. If T is a struct then you also have some boxing/unboxing, but that too isn't as bad as people fear.

In that scenario, IList would be fine by me.

like image 43
Marc Gravell Avatar answered Oct 10 '22 05:10

Marc Gravell