2009-01-01 43 views
1

從C++背景來看,我遇到了基於泛型類型的特定實例重載的障礙。以下情況不起作用,因爲只有一次Foo<T>類的代碼實例已生成,因此在Method內部,this的類型僅爲Foo<T>,而不是Foo<A>Foo<B>,正如我所希望的那樣。在C++中,我習慣於將實例化爲獨特類型的模板。如何通過泛型類型的特定實例重載C#方法

using System.Collections.Generic; 
class A 
{ 
    // Concrete class 
} 

class B 
{ 
    // Concrete class 
} 

class Bar 
{ 
    public void OverloadedMethod(Foo<A> a) {} // do some A related stuff 
    public void OverloadedMethod(Foo<B> b) {} // do some B related stuff 
    public void OverloadedMethod(OtherFoo of) {} // do some other stuff 

    public void VisitFoo(FooBase fb) { fb.Method(this); } 
} 

abstract class FooBase 
{ 
    public abstract void Method(Bar b); 
} 

class Foo<T> : FooBase 
{ 
    // Class that deals with As and Bs in an identical fashion. 
    public override void Method(Bar b) 
    { 
     // Doesn't compile here 
     b.OverloadedMethod(this); 
    } 
} 

class OtherFoo : FooBase 
{ 
    public override void Method(Bar b) 
    { 
     b.OverloadedMethod(this); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<FooBase> ListOfFoos = new List<FooBase>(); 
     ListOfFoos.Add(new OtherFoo()); 
     ListOfFoos.Add(new Foo<A>()); 
     ListOfFoos.Add(new Foo<B>()); 

     Bar b = new Bar(); 
     foreach (FooBase fb in ListOfFoos) 
      b.VisitFoo(fb); 
     // Hopefully call each of the Bar::Overloaded methods 
    } 
} 

有沒有辦法讓這樣的東西在C#中工作?我寧願不必將Foo中的代碼複製爲我想用於其中的每種類型的單獨的類。

編輯: 希望這是一個更清晰一點。

+0

你能澄清嗎?你是否需要它接受一個具有特定類型的泛型類的實例?即MyGenericClass ? – BenAlabaster 2009-01-01 20:22:53

+0

你期望被稱爲哪個超載? – JaredPar 2009-01-01 20:23:38

回答

1

這適用於靜態情況。處理實例函數會有點複雜。這post from Jon Skeet可能提供了一個合理的方式來處理實例方法。

class Program 
{ 
    static void Main(string[] args) 
    { 
     var testA = new Foo<A>(); 
     testA.Method(); 
     var testB = new Foo<B>(); 
     testB.Method(); 
     Console.ReadLine(); 
     var testString = new Foo<string>(); //Fails 
     testString.Method(); 
     Console.ReadLine(); 
    } 
} 

class A { } 
class B { } 
class Bar 
{ 
    public static void OverloadedMethod(Foo<A> a) 
    { 
     Console.WriteLine("A"); 
    } 
    public static void OverloadedMethod(Foo<B> b) 
    { 
     Console.WriteLine("B"); 
    } 
} 
class Foo<T> 
{ 
    static Foo() 
    { 
     overloaded = (Action<Foo<T>>)Delegate.CreateDelegate(typeof(Action<Foo<T>>), typeof(Bar).GetMethod("OverloadedMethod", new Type[] { typeof(Foo<T>) })); 
    } 

    public void Method() 
    { 
     overloaded(this); 
    } 

    private static readonly Action<Foo<T>> overloaded; 
} 
0

編輯:我不確定您是否可以在嘗試時完成此操作。我試過各種各樣的技巧,試圖讓這個工作,並不能編譯。我能做的最好的辦法是將方法調用拉到我的Generic類之外。如果你的方法調用是在外部的,那麼你可以專門定義通用中的T是什麼。但是,在該方法內部,在編譯時,編譯器不知道T是什麼,所以它不知道要調用哪個重載方法。我能看到的唯一方法是使用開關來確定T的類型並手動指定要調用的超載。

我能做的最好的就是這一點,這是不太你以後,但它可以用於類似的效果:

class Stuff<T> 
{ 
    public T value { get; set; } 
} 

class Program 
{ 
    static void DummyFunc(Stuff<int> inst) 
    { 
     Console.WriteLine("Stuff<int>: {0}", inst.value.ToString()); 
    } 

    static void DummyFunc(Stuff<string> inst) 
    { 
     Console.WriteLine("Stuff<string>: {0}", inst.value); 
    } 
    static void DummyFunc(int value) 
    { 
     Console.WriteLine("int: {0}", value.ToString()); 
    } 
    static void DummyFunc(string value) 
    { 
     Console.WriteLine("string: {0}", value); 
    } 
    static void Main(string[] args) 
    { 
     var a = new Stuff<string>(); 
     a.value = "HelloWorld"; 

     var b = new Stuff<int>(); 
     b.value = 1; 

     var c = "HelloWorld"; 
     var d = 1; 

     DummyFunc(a); 
     DummyFunc(b); 
     DummyFunc(c); 
     DummyFunc(d); 
    } 
} 

,並得到輸出:

Stuff<string>: HelloWorld 
Stuff<int>: 1 
string: HelloWorld 
int: 1 

我有四個重載的函數引用兩個引用泛型類(一個用於int和一個字符串)和兩個引用常規類型(一個用於int和一個用於字符串),它一切正常...這是你後?

編輯:這個問題似乎沒有與重載方法的調用,它與你的foreach試圖將列表中的所有項目轉換爲與第一個相同的類型爲了引用重載的方法。不符合該確切定義的第一項將導致編譯失敗。

3

我現在有一個真正完整的代碼來演示這個問題。 OP的注意事項:請在發佈之前嘗試編譯您的代碼。爲了實現這一目標,我需要做很多事情。讓別人儘可能簡單地幫助你是件好事。我也刪除了一堆無關的位。 OtherFoo在這裏並不重要,FooBase也不是。

class A {} 
class B {} 

class Bar 
{ 
    public static void OverloadedMethod(Foo<A> a) { } 
    public static void OverloadedMethod(Foo<B> b) { } 
} 

class Foo<T> 
{ 
    // Class that deals with As and Bs in an identical fashion. 
    public void Method() 
    { 
     // Doesn't compile here 
     Bar.OverloadedMethod(this); 
    } 
} 

是的,這不會編譯。你期望它做什麼,確切地說?請記住,重載分辨率是在編譯時間處執行的,而不是執行時間。正如fallen888所說,你可以投射和調用適當的重載方法 - 但是你認爲編譯器會選擇兩種重載中的哪一種?你想要它與Foo<string>而不是Foo<A>Foo<B>

這一切都證明了.NET泛型確實與C++模板顯然不同,當然......

2

我還沒有嘗試過,但看起來你應該能夠通過使A & B可見(例如,用非循環訪問者模式)來實現你想要的。

0

我希望能找到一個更簡單的方式來做到這一點,但現在我有這個打算:

更換Foo<T>類這些類:

abstract class Foo<T> : FooBase 
{ 
    // Class that deals with As and Bs in an identical fashion. 
} 

class Foo_A : Foo<A> 
{ 
    public override void Method(Bar b) 
    { 
     b.OverloadedMethod(this); 
    } 
} 

class Foo_B : Foo<B> 
{ 
    public override void Method(Bar b) 
    { 
     // Doesn't compile here 
     b.OverloadedMethod(this); 
    } 
} 

,並更改實例來

List<FooBase> ListOfFoos = new List<FooBase>(); 
ListOfFoos.Add(new OtherFoo()); 
ListOfFoos.Add(new Foo_A()); 
ListOfFoos.Add(new Foo_B()); 

這至少不需要公佈Foo<T>中的代碼,只需要我轉發構造函數即可。