2012-06-26 122 views
2

比方說,我有這些類層次結構:在這種情況下,我可以避免反思嗎?

public abstract class Parent { 
} 

public class A : Parent { 
    public void Update() { } 
} 

public class B : Parent { 
    public void Update() { } 
} 

public class C : Parent { 
    public void Update() { } 
    public void Update(bool force) { } 

} 

正如你所看到的,Parent所有後代有一個更新方法,不帶參數。

我想創建一個實用程序類,它可以與任何種類的Parent對象一起使用,並在過程結束時調用Update。我相信Update方法將被執行,所以我寫了這個代碼:

public class ParentUtilities { 
    private static readonly Dictionary<Type, MethodInfo> g_UpdateMethods = new Dictionary<Type, MethodInfo>{ 
     { typeof(A), typeof(A).GetMethod("Update", new Type[] {})}, 
     { typeof(B), typeof(B).GetMethod("Update", new Type[] {})}, 
     { typeof(C), typeof(C).GetMethod("Update", new Type[] {})} 
    }; 

    public static void DoSomething(Parent p) 
    { 
      CalculateTheMeaningOfTheLife(p);    

      g_UpdateMethods[p.GetType()].Invoke(p, null); 
    } 
} 

由於我沒有跨類層次(這是一個第三方組件)控制。我只能改變實用程序類。我怎樣才能避免這種調整?

由於我堅持使用.Net 3.5 SP1,我無法使用動態。

+0

什麼替代? – marko

+4

正如我所說的,我無法控制類層次結構(它來自第三方程序集)。 Parent和Descendants類是在第三方程序集中,但我的實用程序類來自我正在編寫的代碼。 –

+0

您可以構建委託來避免反射的調用。 – leppie

回答

1

如果只是一個已知的,(非常)小集合的子類,那麼你可以做這樣的事情:

public class ParentUtilities 
{ 
    public static void DoSomething(Parent p) 
    { 
     CalculateTheMeaningOfTheLife(p); 

     var a = p as A; 
     if (a != null) 
     { 
      a.Update(); 
      return; 
     } 

     var b = p as B; 
     if (b != null) 
     { 
      b.Update(); 
      return; 
     } 

     var c = p as C; 
     if (c != null) 
     { 
      c.Update(); 
      return; 
     } 
    } 
} 
+0

我開始想,這可能是最簡單的解決方案(有實際3直接後代) –

5

一兩件事你可以不接觸這些類做的就是創建自己的接口IUpdateable,然後創建一個屬於自己的新的並行層次結構中

interface IUpdateable 
{ 
    void Update(); 
} 

public class A : Original.A, IUpdateable {} 

如果你就可以使用自己的葉類,而不是原始的,您可以將該方法編寫爲接受IUpdateable參數。但同時消耗自己的類也不是很困難的(usingalias directives可以幫助),生產他們也不是那麼容易(你需要每次調用創建的原始類的所有實例的原始庫後干預的自定義代碼,如果該實例鍵入爲Parent,您已回到原點)。

不要忘記逼迫原始代碼的作者看到。

+0

在我非常簡單的例子中,這應該是完美的。然而,實際上,我訪問幾十個屬性,方法等,這將需要自動換行的每個屬性,或發佈內部原有答:這將創造更多的問題,它會解決,我認爲 –

+0

@SteveB:你不要」 t實際上需要包裝任何東西。只需定義接口就足夠了,實現者將是另外的「空」類。 – Jon

+1

請注意,如果你是實例化A,B和C類的人,那麼這隻會起作用。如果它們中的任何一個是通過工廠方法或類似方法創建的,則這將失敗。 – AhHatem

0

創建一個名爲UpdatableParent一個臨時類,還帶有一個Update()方法,並從中獲得來自它的所有其他類。然後使用UpdateableParent作爲DoSomething()參數的類型。

+0

我不能改變既不是父類,也沒有後裔(A,B,C) –

2

您可以創建一個定義良好的接口實現的包裝類。

使用

class Program 
{ 
    static void Main(string[] args) 
    { 
     A a = new A(); 
     IUpdatable wrapper = new AWrapper(a); 
     wrapper.Update(); // prints A.Update 
    } 
} 

包裝類和接口

interface IUpdatable 
{ 
    void Update(); 
} 


public abstract class Parent { } 

public class A : Parent 
{ 
    public void Update() 
    { 
     Console.WriteLine("A.Update"); 
    } 
} 

public class AWrapper : IUpdatable 
{ 
    public A Inner { get; private set; } 
    public AWrapper(A a) 
    { 
     Inner = a; 
    } 

    public void Update() 
    { 
     Inner.Update(); 
    } 
} 
+0

這個代碼將要求所有來電到DoSomething方法創建一個包裝實例,而不是簡單地傳遞原始對象。我可以接受實用方法中的一些複雜性,但不是來自調用代碼(畢竟這是一種實用方法,目的是簡化事情) –

相關問題