2011-12-22 100 views
3

在C++中,你可以從一個模板參數調用方法的,像這樣:是否可以在C#中調用泛型參數的方法?

template<class T> class foo 
{ 
    T t; 
    t.foo(); 
} 

但在C#中,看起來這是不可能的:

class foo<T> 
{ 
    T t; 
    public void foo() { 
    t.foo(); // Generates a compiler error 
    } 
}; 

我想這大概是不可能的在C#中,是嗎?

回答

9

是的,如果你知道泛型類型的佔位符T實現了從基類或接口的成員,您可以使用where條款約束型T該基類或接口。

public interface IFooable 
{ 
    void Foo(); 
} 

// ... 

public class Foo<T> where T : IFooable 
{ 
    private T _t; 

    // ... 

    public void DoFoo() 
    { 
     _t.Foo(); // works because we constrain T to IFooable. 
    } 
} 

這使得一般類型佔位符T到被視爲IFooable。如果你做而不是限制泛型中的泛型類型佔位符,那麼它被限制爲object這意味着只有object的成員對泛型可見(即,你只能看到對object引用可見的成員,但調用任何被覆蓋的成員將調用適當的覆蓋)。

注:這是另外很重要的,因爲事情像運算符重載(記住,符重載,未覆蓋),所以如果你有這樣的代碼:

public bool SomeSuperEqualsChecker<T>(T one, T two) 
{ 
    return one == two; 
} 

這將始終使用object==即使Tstring。然而,如果我們有:

public bool SomeSuperEqualsChecker<T>(T one, T two) 
{ 
    // assume proper null checking exists... 
    return one.Equals(two); 
} 

這與string因爲Equals()被覆蓋,不超載正常工作。

所以,長和短只是記住一個無約束的通用佔位符確實代表任何類型,但唯一可見的調用和操作是那些在object上可見的調用和操作。

除了接口/基類的限制,也有一些其他方面的限制:

  • new() - 意思是說,泛型類型的佔位符必須有一個默認的構造函數
  • class - 意思是說,泛型類型的佔位符必須是引用類型
  • struct - 意思是一般類型的佔位符必須是一個值類型(枚舉,原始的,結構等)

例如:

public class Foo<T> where T : new() 
{ 
    private T _t = new T(); // can only construct T if have new() constraint 
} 

public class ValueFoo<T> where T : struct 
{ 
    private T? _t; // to use nullable, T must be value type, constrains with struct 
} 

public class RefFoo<T> where T : class 
{ 
    private T _t = null; // can only assign type T to null if ref (or nullable val) 
} 

希望這會有所幫助。

+0

+1很好的答案! – Yuck 2011-12-23 22:23:49

3

您需要爲您的方法添加type constraint

public interface IFoo { 
    void Foo(); 
} 

public class Foo<T> where T : IFoo { 
    T t; 
    public void foo() { 
     t.Foo(); // Generates a compiler error 
    } 
} 
3

如果您願意接受泛型類型的約束,這意味着您的泛型類型必須受限於從某個基類派生或實現某個接口。

例子:

abstract class SomeBase 
{ 
    public abstract DoSomething(); 
} 

// new() ensures that there is a default constructor to instantiate the class 
class Foo<T> where T : SomeBase, new() 
{ 
    T t; 

    public Foo() 
    { 
     this.t = new T(); 
     this.t.DoSomething(); // allowed because T must derive from SomeBase 
    } 
} 
11

您發現之間模板仿製藥的差異。儘管它們看起來很相似,但實際上卻完全不同。

一個模板只需要爲實際提供的類型參數是正確的;如果你提供一個沒有foo方法的T,那麼編譯失敗;如果僅提供具有foo的類型參數,則編譯成功。

相比之下,任何可能的T都必須正確對應於。由於我們沒有證據表明每個可能的T都會有一個foo的方法,所以通用是非法的。

相關問題