views:

108

answers:

1

I have a few generic classes that implement a common non-generic interface. I create my generic objects and add them to a list. How can I use LINQ, or any other method for that matter, to filter the list by the generic type. I do not need to know T at run-time. I added a type property to the interface and used LINQ to filter by it but I was hoping to use the is operator. Here's a simple example I threw together.

Any Ideas?

interface IOperation
    {
        object GetValue();
    }
    class Add<T> : IOperation
    {
        public object GetValue()
        {
            return 0.0;
        }
    }
    class Multiply<T> : IOperation
    {
        public object GetValue()
        {
            return 0.0;
        }
    }


    private void Form1_Load(object sender, EventArgs e)
    {
        //create some generics referenced by interface
        var operations = new List<IOperation>
        {
            new Add<int>(),
            new Add<double>(),
            new Multiply<int>()
        };

        //how do I use LINQ to find all intances off Add<T> 
        //without specifying T?

        var adds =
            from IOperation op in operations
            where op is Add<> //this line does not compile
            select op;
    }
+3  A: 

You can just compare the underlying non-parameterized type names:

var adds =
    from IOperation op in operations
    where op.GetType().Name == typeof(Add<>).Name
    select op;

Note that in the next version of C#, this will be possible due to variance:

var adds =
    from IOperation op in operations
    where op is Add<object>
    select op;
Dario
+1 for you sir. Well done!
Steve
+1 ...............
eglasius
Remember, covariance and contravariance in C# 4 only applies to generic interfaces and delegates, not to classes and structs, and the type arguments must be reference types. Would all those criteria be met in this example?
Eric Lippert
Not to classes? I can pretty well use `ReadonlyList<int>` with `ReadonlyList<object>`, can't I?
Dario
Oops, you're right about variance. We'd need interfaces thou.
Dario
Absolutely you cannot use a ReadOnlyList<int> as a ReadOnlyList<object>. There is no covariance on class types, and variance requires that both type arguments be reference types. The reasoning why this is disallowed is straightforward: suppose it were allowed and deduce contradiction. The indexer of ReadOnlyList<int> puts an unboxed integer on the stack. A caller who has a reference to a ReadOnlyList<object> expects a call to the indexer to put an object reference on the stack. An unboxed integer is not an object reference, and therefore we have broken type safety.
Eric Lippert