1

我想实现一个泛型类,这将允许安全蒙上了通用的方法,请参见例如:如何在C#中使用泛型进行安全的投射?

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

然而,编译器告诉我,Foo<T>.SafeCast<R>() does not define parameter 'T'。我明白这个消息,我不能在方法中指定T的约束,因为它没有在方法中定义。但是我怎样才能指定一个逆向约束?

+0

如果T不是从R派生的,你会期望什么行为? – Jake 2010-03-30 22:01:32

+1

@Jake:这里的意图是,如果没有选择R使得T可转换为R,那么程序将无法编译。例如,您可能有Foo f并且说f.SafeCast 。如果你说f.SafeCast 那么这将无法编译。可悲的是,我们不支持这个功能。 – 2010-03-30 22:06:46

回答

17

C#没有这种约束。约束必须是“R必须可兑换 X”的形式;我们不支持“R必须可兑换 X”形式的限制。

这是不幸的,因为它使涉及逆变换的某些情况更容易。

Scala允许这样的约束,顺便说一句。

有趣的是,你可以做你想做的与扩展方法,但你必须是多余的,当你把它叫做:

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

现在,你可以说:

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

在C#4你的代码在很大程度上是不必要的;如果T是参考类型,则在C#4中的T中安全地协变为IEnumerable<T>

0

public IEnumerable<R> SafeCast<T,R>() where T : R是我认为您需要这样做的签名。这不是你想要的吗?

+3

不,这个重新声明T. OP想要外层T. – 2010-03-30 22:04:50

+2

啊,我明白了。不会删除我的答案,以便人们可以从您的评论中学习,以及为什么我的建议不是解决方案。 :-) – Jaxidian 2010-03-30 22:17:04