views:

332

answers:

6

I have the following code

class Program
    {
        static void Main(string[] args)
        {
            List<A> aList = new List<A>();

            var aObj = new A();

            aObj.Go(aList.Cast<IB>());
        }
    }

    class A : IB
    {
        public void Go(IEnumerable<IB> interfaceList)
        {
            foreach (IB ibby in interfaceList)
            {
                Console.WriteLine("Here");
            }
        }
    }

    interface IB
    {
        void Go(IEnumerable<IB> interfaceList);
    }

}

I originally tried passing a List but that doesn't work. After a lot of help from SO I found that passing IEnumerable is the only way to get the objects across as .ofType(IB).

Unfortunately for me, in my code the following line will be executed thousands of times:

aList.Cast<IB>();

I was wondering if anyone knew how it was implemented algorithmically (in IL) and what its time order is.

That is to say, is it faster than a foreach loop that just casts each item, or is that exactly what it does?

EDIT The main class needs to maintain a list of the actual objects. But the reader is only allowed to touch them through the interface.

+10  A: 

You should change Go to:

public void Go<T>(IEnumerable<T> interfaceList)
    where T : IB
{
    foreach (IB ibby in interfaceList)
    {
        Console.WriteLine("Here");
    }
}

Then you'll be fine with no need to call Cast. I suspect the source code implementation of Cast is pretty simple, although I believe it changed between 3.5 and 3.5SP1. However, it probably needs to set up a new state machine etc in the normal iterator block fashion. Better to avoid it if possible.

Even though the new method is generic, type inference should usually take care of it for you so you don't need to specify T explicitly.

Jon Skeet
This might be completely changing the question, but what if A needed to have an internal list of IBs that exactly mirrored the main list of A's?
@devinb: I'm not really sure what you mean. Do you mean as a member variable? You'd have to make A generic; then you could use the same trick. If that's not enough information, I suggest you ask a new question for this bit giving more details.
Jon Skeet
+5  A: 

Why not just declare the list like:

List<IB> aList = new List<IB>();

Is there something in particular that requires you to have a list of the concrete classes?


So in that case I'd make the list part of the domain. Have an interface like IIBCollection (for example), expose the methods on that you want the reader to be able to access. For example:

interface IIBCollection{
    IEnumerable<IB> IBs { get; }
}

// and in your implementation you can do

IEnumerable<IB> IBs { 
    get { 
        foreach(IB ib in innerList) yield return ib; 
}}
jonnii
Yes, because the main class needs to maintain a list of the actual objects, but the reader class is only allowed to access the interface.
Sorry if I'm a little slow. But you're saying that the main class (EnvironmentClass in my actual case) should implement IIBCollectionI'm just not sure what the IIBCollection interface should apply to.
You'd have something like Environment, EnvironmentCollection, IEnvironment and IEnvironmentCollection. The Go() method would live on the Collection.
jonnii
+1  A: 

It's implemented internally as a CastIterator which is slightly slower than a foreach that casts each item.

Jeff Moser
A: 

The Cast method will just loop through the list and cast each item.

If you are going to use the list thousands of time, just store the result of the casting as a list.

If that is not possible (i.e. you change the list each time), consider working with a List<IB> instead of a List<A>.

Guffa
A: 

Isn't this what covariance in C# is for? I don't see what you're trying to do, so I can't comment on why it's exeuted thousands and thousands of times.

Dave Van den Eynde
A: 

It would be a fairly simple matter just to benchmark the two methods (Cast extension method and a for loop with a cast). But given that Cast is an extension method of the Enumerable class and deals generically with IEnumerables, I'd imagine this is precisely it's implementation. If you want the greatest speed, it may be best to implement your own extension method that works specifically on List (gets each element by its index), which should be slightly faster given the overhead of iterators. Still, both methods should take O(n) time, so the difference ought not be huge. It's something worth benchmarking, nonetheless...

Noldorin