2014-01-22 43 views
2

我有下面的類層次結構:上溯造型到一個泛型類型

class A { 
/// stuff 
} 

class B : A { 
/// stuff 
} 

class C<T> : B { 
    /// stuff 
} 

然後某處完全不同的,我有以下三種方法:現在

public void foo(A a) { 
} 

// overload 1 
public void bar(B b) { 
} 

// overload 2 
public void bar<T>(C<T> ct) { 
} 

,不管出於什麼原因,我需要調用如果A實際上是B類型的,我需要調用重載1,如果A實際上是C類型(無論T是什麼),我需要調用超載2.爲了完整性,如果A不是B或C,則什麼都不做。

現在,我使用的是Type類的IsAssignableFrom方法來決定是否上轉換到B是可能的:

public void foo(A a) { 
    if (typeof(B).IsAssignableFrom(a)) { 
     bar((B)a); 
    } 
} 

但是這需要在C變種爲好。所以問題是,我該如何執行這個upcast?反射?動力學?我們使用.NET 4,所以在C#5中引入的任何東西都無法使用。

回答

3

使用dynamic。它將使得方法解析在運行時而不是編譯時發生,所以你會得到最適合實際實例類型的方法。

bar((dynamic)value); 
+0

This Works!謝謝。一個問題是你必須有一個對Microsoft.CSharp程序集的引用。 – syazdani

+0

考慮到「如果A既不是B也不是C,什麼都不做」的說明,這個動態解決方案將不會說明這個問題,對嗎? –

+0

它不但與我已有的IsAssignableFrom結合使用,而且還可以工作。 – syazdani

6

然後某處完全不同的,我有以下三種方法:

,說明了第一電位解決您的問題。不要做「完全不同的地方」。使bar成爲A的虛擬成員,然後foo調用它。

第二種可能的解決方案是使用訪問者模式。

interface IVisitor 
{ 
    void Visit(B b); 
    void Visit<T>(C<T> c); 
} 
class A 
{ 
    public virtual void Accept(IVisitor v) 
    { } // Do nothing 
} 
class B : A 
{ 
    public override void Accept(IVisitor v) 
    { v.Visit(this); } 
} 
class C<T> : B 
{ 
    public override void Accept(IVisitor v) 
    { v.Visit<T>(this); } 
} 
class P 
{ 
    class Visitor : IVisitor 
    { 
     public void Visit(B b) { bar(b); } 
     public void Visit<T>(C<T> c) { bar<T>(c); } 
    } 
    public static bar(B b) { } 
    public static bar<T>(C<T> c) { } 
    public static void foo(A a) 
    { 
     a.Accept(new Visitor()); 
    } 
} 

但是讓我們假設你不能修改ABC<T>。現在

,不管出於什麼原因,我需要調用給定的實際類型A.也就是說,「右」從FOO條如果A實際上是B型的,我需要調用超載1,如果A實際上是C類型的(無論T可能是什麼),我需要調用重載2.爲了完整性,如果A不是B或C,則什麼都不做。

首先是容易的:

public void foo(A a) 
{ 
    if (a is B) bar((B)a); 

然而,通用的亞型是困難的;不幸的是,if (a is C<?>) bar((C<?>)a;沒有任何機制。

你將不得不使用反射或dynamic。請注意,如果dynamic在運行時無法找到匹配的bar,那麼它將拋出,而不是執行任何操作。