Some library specifications in other domains (like the C++ STL) provide clear guarantees on performance figures on add, remove, access, sort, memory consumption, memory layout, etc. of the provided containers and their iterators.
Since .Net/C# is not a high-performance environment, this seems to be lesser of a focus. At least I don't know of a systematic analysis and guarantees of containers in the .Net world.
If you need to know which container is faster for your application, you best measure it. You have several standard containers at hand in C# (see
System.Collections.Generic[
^] and
System.Collections[
^] namespaces.
Beside that, you have the C# native object arrays (e.g.
string[]
).
General speaking:
- Hash tables (
Directory<...>
objects) are for linear access time in average (assuming you have a decent hash key for your objects), but you have no ordering and in worst case, you have bad performance when all hash key collaps to all the same. List<...>
objects have good performance for random access and adding at the end, but are bad for searching (e.g. check if the list contains some entry). They are good for general purpose storing elements that have a defined order and for random access.- Other more specialized containers focus on other aspects (e.g. sorted while adding, Set operations, fast manipulation like random location insertion and deletion, fast adding at one end and extracting at the other end, fast adding and extracting at one end, etc.)
You see, that there are a few general purpose containers and several special purpose containers that serve a specific set of operations well (under given circumstances) and not so well in the other cases.
Decide on what your main application of the container is and use the most appropriate container for that. If performance is not sufficient, measure the performance drain and only then decide on a remedy.
Beside containers, you have the option to avoid containers in many situations.
If you work with LINQ, check out for not needed
.ToList()
and similar calls.
LINQ bases on defered evaluation of element sequences (also known
iterators). I.e. if you query database data through LINQ, you always get deferred evaluation. If you implement such queries "carelessly", you get unneeded data access which may cost a lot of execution time, e.g.
"careless" | more performant |
---|
List<string> GetHugeData()
{
return (from record in db.MyHugeTable
select record.Text
).ToList();
}
...
if (GetHugeData().Count > 0)
{
...
} |
IQueryable<string> GetHugeData()
{
return from record in db.MyHugeTable
select record.Text;
}
bool HasElements<T>(IQueryable<T> it)
{
return it != null
&& it.GetEnumerator().MoveNext();
}
...
if (HasElements(GetHugeData()))
{
...
} |
If you have LINQ to Object or LINQ to XML, you would use
IEnumerable<...>
instead of
IQueryable<...>
.
Cheers
Andi