Royi Namir
Royi Namir

Reputation: 148524

Is it possible to count something from general container in c#?

I have an object.

This object is casting an Items Container (I don't know what items, but I can check).

But is there any code which can help me find how many items it contains?

I mean

 object[] arrObj = new object[2] {1, 2};
 object o = (object)arrObj;

In this case arrObj is an array so I can check:

((Array)o).Length //2

But what if I have those 2 others ?

 ArrayList al = new ArrayList(2);
           al.Add(1);
           al.Add(2);
 object o = (object)al ;

and

 List<object> lst= new List<object>(2);
 object o = (object)lst;

Is there any general code which can help me find how many items are in this casted object (o in this samples) ?

Of course I can check if (o is ...) { } but Im looking for more general code.

Upvotes: 2

Views: 256

Answers (3)

Jon Skeet
Jon Skeet

Reputation: 1500675

Well the most basic interface it could implement would be IEnumerable. Unfortunately even Enumerable.Count from LINQ is implemented for IEnumerable<T>, but you could easily write your own:

public static int Count(IEnumerable sequence)
{
    // Shortcut for any ICollection implementation
    var collection = sequence as ICollection;
    if (collection != null)
    {
        return collection.Count;
    }

    var iterator = sequence.GetEnumerator();
    try
    {
        int count = 0;
        while (iterator.MoveNext())
        {
            count++;
        }
        return count;
    }
    finally
    {
        IDisposable disposable = iterator as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }
}

Note that this is basically equivalent to:

int count = 0;
foreach (object item in sequence)
{
    count++;
}

... except that because it never uses Current, it wouldn't need to do any boxing if your container was actually an int[] for example.

Call it with:

var sequence = container as IEnumerable;
if (sequence != null) 
{
    int count = Count(sequence);
    // Use the count
}

It's worth noting that avoiding boxing really is a bit of a micro-optimization: it's unlikely to really be significant. But you can do it once, just in this method, and then take advantage of it everywhere.

Upvotes: 2

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174329

You can cast to the interface every container implements: IEnumerable. However, to be more performant, it is a good idea to first try IEnumerable<T>:

var count = -1;
var enumerable = lst as IEnumerable<object>;
if(enumerable != null)
    count = enumerable.Count();
else
{
    var nonGenericEnumerable = lst as IEnumerable;
    count = nonGenericEnumerable.Cast<object>().Count();
}

For Count() to be available, you need to add using System.Linq; to your .cs file.

Please note that this code has one big advantage: If the collection implements ICollection<T> - like List<T> or strong typed arrays of reference types - this code executes in O(1) [Assuming the concrete implementation of ICollection<T>.Count executes in O(1)]. Only if it doesn't - like ArrayList or strong typed arrays of value types - does this code execute in O(n) and additionally, it will box the items in the case of an array of value types.

Upvotes: 4

Daniel A. White
Daniel A. White

Reputation: 190943

You could use linq.

var count = ((IEnumerable)o).Cast<object>().Count();

Ensure that the type o has implements IEnumerable and that you have using System.Linq at the top of your file.

Upvotes: 3

Related Questions