2014-01-28 66 views
3

我希望能是這樣的:C#泛型能做到這一點嗎?

class A<T1, T2> 
{ 
    public void Call(T1 arg1, T2 arg2) 
    { 
     B b = new B(); 
     b.DoSomething(arg1); // determine which overload to use based on T1 
     b.DoSomething(arg2); // and T2 
    } 
} 

class B 
{ 
    public void DoSomething(int x) 
    { 
     // ... 
    } 

    public void DoSomething(float x) 
    { 
     // ... 
    } 
} 

我知道它可以用的​​if/else檢查,但似乎並不很優雅,尤其是當我有20多個類型選擇做從。

+7

你想解決什麼問題? –

+3

你真的嘗試過嗎? –

+2

我想你想'動態',而不是泛型 –

回答

8

如果你想輸入的安全,你能做的最好的大概是:

class A<T1, T2> 
{ 
    public void Call<T>(T1 arg1, T2 arg2) where T : IDoSomething<T1>, IDoSomething<T2>, new() 
    { 
     T b = new T(); 
     b.DoSomething(arg1); 
     b.DoSomething(arg2); 
    } 
} 

public interface IDoSomething<T> 
{ 
    void DoSomething(T arg); 
} 

public class B : IDoSomething<int>, IDoSomething<float> 
{ 
    void IDoSomething<int>.DoSomething(int arg) 
    { 
     Console.WriteLine("Got int {0}", arg); 
    } 

    void IDoSomething<float>.DoSomething(float arg) 
    { 
     Console.WriteLine("Got float {0}", arg); 
    } 
} 

,您可以使用這樣的:

var a = new A<int, float>(); 
a.Call<B>(1, 4.0f); 
+0

+1,用於類型安全並描述完成所需功能的最嚴格實施。 –

4

此方法不是類型安全的或建議的

可以聲明變量爲dynamic,這意味着它的類型將在運行時解析,而不是編譯時。

public void Call(dynamic arg1, dynamic arg2) 
{ 
    B b = new B(); 
    b.DoSomething(arg1); // determine which overload to use based on T1 
    b.DoSomething(arg2); // and T2 
} 

要注意的是,如果arg1結果是,可以說,一個字符串,並沒有適當的超載存在,你會得到一個RuntimeBinderException。 此外,還有輕微的性能下降,因爲您推遲了類型解析。

+0

我不能在我正在使用的環境中使用動態,所以這不是一個選項。 –

+0

我認爲這是一個愚蠢的使用'動態',並不一定回答這個問題。問題是「C#泛型能變得這麼酷嗎?」並排除使用'動態'。 –

+0

@MichaelJ。灰色其實,堆棧溢出的很多帖子([1](http://stackoverflow.com/questions/7210017/method-overload-resolution-using-dynamic-argument),[2](http://stackoverflow.com/ questions/5835989/method-overloading-and-dynamic-keyword-in-c-sharp))顯示了這個'dynamic'關鍵字的用法。我不是說你應該使用它(我不會),我表明你可以使用它來動態確定應該調用哪種方法重載(這似乎是OP的問題,也是他的問題的核心) )。 – dcastro

0

是的,他們是冷靜。

但是,它只能用於繼承層次結構,因爲在您的示例中:arg1必須是int,而arg2必須是float。您將收到編譯器錯誤,因爲您的類型聲明T1,T2不限於類型float和int。

如果arg1是BaseA,arg2是BaseB,那麼這個例子會更多。

然後,你將宣佈A類,像這樣:

class A<T1, T2> where T1: BaseA, T2: BaseB 

現在對於其中T1從BaseA繼承,任何情況下,等它會奏效。

當您使用類A時,運行時將知道實際正在使用哪種類型,並選擇正確的過載。

+0

請注意,這不適用於原始數據類型:[C#泛型約束的泛型方法拒絕從整型轉換爲泛型類型](http://stackoverflow.com/questions/11770882/c-sharp-generic-method -with整數約束-拒絕到鑄從整數到T)。 OP實際上可能使用類的類型,但問題中的例子使用'int'和'float' – valverij

0

你可以做到這一點,但只有在特定情況下,如果你可以對泛型使用where約束,並且編譯器知道該期待什麼。

但是,除非您使用dynamic,否則它必須知道該發生什麼。還請注意,通用類型約束必須是類或接口。它不能是(例如)int

簡單的示例來編譯和運行得很好:

static void Main(string[] args) 
{ 
    A<C, D> test = new A<C, D>(); 
    test.Call(new Cimpl(), new Dimpl()); 
} 

class A<T1, T2> where T1 : C where T2 : D 
{ 
    public void Call(T1 arg1, T2 arg2) 
    { 
     B b = new B(); 
     b.DoSomething(arg1); // determine which overload to use based on T1 
     b.DoSomething(arg2); // and T2 
    } 
} 

class Cimpl : C { } 

class Dimpl : D { } 

interface C 
{ } 

interface D 
{ } 

class B 
{ 
    public void DoSomething(C x) 
    { 
     // ... 
    } 

    public void DoSomething(D x) 
    { 
     // ... 
    } 
}