views:

67

answers:

3

In C#, currently i'm doing the following code to filter out a specific set of classes that inherit from the CaptureType that is passed to the method.

    public static CaptureType[] ListPluginsWith<CaptureType>()
    {
        List<CaptureType> plugins = new List<CaptureType>();
        foreach (var plugin in Bot.AutoPlugins)
        {
            CaptureType plug;
            try
            {
                if ((plug = (CaptureType)plugin.Interface) != null)
                {
                    plugins.Add(plug);
                }
            }
            catch
            {
                //doesn't inherit
            }
        }
        return plugins.ToArray();
    }

is there a more efficient/better/faster way to do this? if so, please let me know :)

+3  A: 
if (plugin.Interface is CaptureType)
{
    // inherits
}

or even

return Bot.AutoPlugins.Where(i => i.Interface is CaptureType).ToArray();

UPD: if CaptureType is strongly required to be returned:

return Bot.AutoPlugins.Where(i => i.Interface is CaptureType)
                      .Select(i => i as CaptureType)
                      .ToArray();

(yes, now it looks a little more bloated, but there is another laconic answer with OfType() in this thread, so i will not repeat it)

zerkms
Note your second version actually returns an array of `Plugin`, not `CaptureType`. You'd have to couple it with a call to `Select()`.
Dean Harding
@Dean Harding: yes, i've seen that but i bet that it is suitable solution too and when necessary - this array will be casted implicitly.
zerkms
+3  A: 

I would actually suggest the following:

public static IEnumerable<CaptureType> ListPluginsWith<CaptureType>()
   where CaptureType : class
{
    foreach (var plugin in Bot.AutoPlugins)
    {
        CaptureType plug = plugin.Interface as CaptureType;
        if (plug != null)
            yield return plug;
    }
}

This has a number of advantages:

  1. If you use the is keyword, you basically end up doing two type casts (the evaluation of x is y is basically a type cast and has the same performance characteristics) so if you do (if (x is Y) { blah = (Y)x } you're doing two casts instead of just one that as and a null check requires.
  2. By using an interator (i.e. the yield return stuff) you don't need to create a temporary List<CaptureType> in memory, convert it to an array and then return the array.

Also note the where CaptureType : class. Since CaptureType is an interface, you can be sure that it'll always pass, but that constraint is required in order to use the as keyword. If you have a "base" interface that all your plugins implement (e.g. IPlugin maybe) then you could replace the where CaptureType : class with where CaptureType : IPlugin instead.

Dean Harding
+1 for noting the efficiency of the as keyword.
Tim
I can't use the as keyword as the capture type is going to be an interface, so i can't have the where : class... but thankyou for your input
Tommy
I do have an interface that all my plugins implement, yes, thank you for that.
Tommy
A: 

I would suggest a simple

return Bot.AutoPlugins.Select (p => p.Interface).OfType<CaptureType> ().ToArray ();

EDIT:

Thinking more, this is potentially less efficient than doing the a Where then Select combination, as in my example you do the select for every item, then limit by type...

Pete