views:

176

answers:

2

I want to implement a generic method on a generic class which would allow to cast safely, see example:

public class Foo<T> : IEnumerable<T>
{
    ...
    public IEnumerable<R> SafeCast<R>()
        where T : R
    {
        return this.Select(item => (R)item);
    }
}

However, the compiler tells me that Foo<T>.SafeCast<R>() does not define parameter 'T'. I understand this message that I cannot specify a constraint on T in the method since it is not defined in the method. But how can I specify an inverse constraint?

+13  A: 

C# does not have that kind of constraint. A constraint has to be of the form "R must be convertible to X"; we do not support constraints of the form "R must be convertible from X".

Which is unfortunate, since it makes certain scenarios involving contravariant conversions easier.

Scala permits such a constraint, incidentally.

Interestingly enough, you can do what you want with an extension method, but you then have to be redundant when you call it:

public static IEnumerable<R> SafeCast<T, R>(this IEnumerable<T> x) where T : R
{
    return x.Cast<R>();
}

Now you can say:

IEnumerable<Giraffe> giraffes = whatever;
IEnumerable<Animal> animals = giraffes.SafeCast<Giraffe, Animal>();

In C# 4 your code will be largely unnecessary; IEnumerable<T> is safely covariant in T in C# 4 if T is a reference type.

Eric Lippert
A: 

public IEnumerable<R> SafeCast<T,R>() where T : R is the signature I think you need to do this. Does that not do what you want?

Jaxidian
No, that redeclares T. The OP wants the outer T.
Eric Lippert
Ahh, I see. Will not delete my answer so people can learn from your comment and why my suggestion is NOT a solution. :-)
Jaxidian