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