2009-04-17 83 views
12

我有一個類在客戶端應用程序和服務器應用程序中使用。 在服務器應用程序中,我向類槽延伸方法添加了一些功能。很棒。現在我想多一點:虛擬擴展方法?

我的課(B)從另一個課(A)繼承。

我想附加一個虛擬功能給A(比方說Execute()),然後在B中實現該功能,但僅限於服務器。 Execute()方法需要執行只能在服務器上執行的操作,只使用服務器知道的類型。

有許多類型繼承自A,就像B一樣,並且我想爲它們中的每一個實現Execute()。

我希望我可以添加一個虛擬的擴展方法給A,但這個想法似乎並沒有飛。我正在尋找最優雅的方式來解決這個問題,無論是否使用擴展方法。

回答

4

不,不存在虛擬擴展方法之類的東西。你可以使用重載,但不支持多態。這聽起來像你可能想看看像依賴注入(等)有不同的代碼(依賴)在不同的環境中添加 - 在常規虛擬方法使用它:

class B { 
    public B(ISomeUtility util) { 
     // store util 
    } 
    public override void Execute() { 
     if(util != null) util.Foo(); 
    } 
} 

然後用DI框架來提供運行時特定於服務器的ISomeUtility實現到B。你可以做同樣的事情與中央static註冊表(IOC,但沒有DI):

override void Execute() { 
     ISomeUtility util = Registry.Get<ISomeUtility>(); 
     if(util != null) util.Foo(); 
    } 

(在這裏你需要寫Registry等;再加上在服務器上,註冊ISomeUtility實現)

+0

感謝馬克。我會執行這樣的事情。對我來說這比較棘手,因爲我將這些類序列化,然後通過服務器到客戶端的連線將它們發送回去。所以傳統的DI可能有點棘手,但我想我可以實現類B的服務器端等價物(可能繼承自B),並且當客戶端向服務器發送B的一個實例時,我必須將其替換爲ServerB的新實例。 – Lucas 2009-04-17 08:38:01

+0

註冊表方法可以在序列化中正常工作。我使用這種方法做與WCF對象的程序集共享... – 2009-04-17 08:50:06

0

虛擬意味着OOP方式的繼承,擴展方法是「只是」靜態方法,通過一點語法糖,編譯器允許你假裝調用其第一個參數類型的實例。所以不,虛擬擴展方法是不可能的。

查看Marc Gravell爲您的問題解決問題的答案。

0

您可以實現服務註冊。示例(服務器端):

static IDictionary<Type, IService> serviceRegister; 

public void ServerMethod(IBusinessType object) 
{ 
    serviceRegister[obect.GetType()].Execute(object); 
} 

你需要什麼,而在你的服務器服務,實現服務器端的功能,而不是擴展方法。我不會在擴展方法上投入太多的邏輯。

0

讓我檢查一下:您有一個繼承自A的類層次結構,可能是根據您的業務領域構建的。然後,您想要根據類執行的位置添加行爲。到目前爲止,您已經使用過擴展方法,但是現在您發現無法根據您的類層次結構改變它們。你在服務器上附加了哪些行爲?

如果是事務管理和安全性等問題,通過依賴注入實現的策略應該能夠很好地工作。您也可以考慮通過代表和lambda表達式實現Strategy pattern,以獲取更多限制版本的DI。但是,目前尚不清楚客戶端代碼當前如何在服務器上使用您的類及其擴展方法。其他類如何依賴於如何添加服務器端功能?他們是僅服務器端的類,目前希望找到擴展方法嗎?

在任何情況下,聽起來您將需要仔細的可測試性設計和測試策略,因爲您正在沿着兩個同時維(繼承層次結構,執行環境)引入變體。我正在使用單元測試,我相信?檢查您選擇的解決方案(例如DI通過配置)是否與測試和嘲諷很好地交互。

2

我會建議像下面這樣的東西。可以通過添加對檢測不具有調度映射的中間類層次結構類型的支持並根據運行時層次結構調用最近的調度方法來改進此代碼。它也可以通過使用反射來檢測ExecuteInteral()的超載並將它們自動添加到調度映射中。

using System; 
using System.Collections.Generic; 

namespace LanguageTests2 
{ 
    public class A { } 

    public class B : A {} 

    public class C : B {} 

    public static class VirtualExtensionMethods 
    { 
     private static readonly IDictionary<Type,Action<A>> _dispatchMap 
      = new Dictionary<Type, Action<A>>(); 

     static VirtualExtensionMethods() 
     { 
      _dispatchMap[typeof(A)] = x => ExecuteInternal((A)x); 
      _dispatchMap[typeof(B)] = x => ExecuteInternal((B)x); 
      _dispatchMap[typeof(C)] = x => ExecuteInternal((C)x); 
     } 

     public static void Execute(this A instance) 
     { 
      _dispatchMap[instance.GetType()](instance); 
     } 

     private static void ExecuteInternal(A instance) 
     { 
      Console.WriteLine("\nCalled ToString() on: " + instance); 
     } 

     private static void ExecuteInternal(B instance) 
     { 
      Console.WriteLine("\nCalled ToString() on: " + instance); 
     } 

     private static void ExecuteInternal(C instance) 
     { 
      Console.WriteLine("\nCalled ToString() on: " + instance); 
     } 
    } 

    public class VirtualExtensionsTest 
    { 
     public static void Main() 
     { 
      var instanceA = new A(); 
      var instanceB = new B(); 
      var instanceC = new C(); 

      instanceA.Execute(); 
      instanceB.Execute(); 
      instanceC.Execute(); 
     } 
    } 
} 
3

您可以使用新的動態類型的功能,以避免建設的類型註冊表的方法:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using visitor.Extension; 

namespace visitor 
{ 
    namespace Extension 
    { 
     static class Extension 
     { 
      public static void RunVisitor(this IThing thing, IThingOperation thingOperation) 
      { 
       thingOperation.Visit((dynamic)thing); 
      } 

      public static ITransformedThing GetTransformedThing(this IThing thing, int arg) 
      { 
       var x = new GetTransformedThing {Arg = arg}; 
       thing.RunVisitor(x); 
       return x.Result; 
      } 
     } 
    } 

    interface IThingOperation 
    { 
     void Visit(IThing iThing); 
     void Visit(AThing aThing); 
     void Visit(BThing bThing); 
     void Visit(CThing cThing); 
     void Visit(DThing dThing); 
    } 

    interface ITransformedThing { } 

    class ATransformedThing : ITransformedThing { public ATransformedThing(AThing aThing, int arg) { } } 
    class BTransformedThing : ITransformedThing { public BTransformedThing(BThing bThing, int arg) { } } 
    class CTransformedThing : ITransformedThing { public CTransformedThing(CThing cThing, int arg) { } } 
    class DTransformedThing : ITransformedThing { public DTransformedThing(DThing dThing, int arg) { } } 

    class GetTransformedThing : IThingOperation 
    { 
     public int Arg { get; set; } 

     public ITransformedThing Result { get; private set; } 

     public void Visit(IThing iThing) { Result = null; } 
     public void Visit(AThing aThing) { Result = new ATransformedThing(aThing, Arg); } 
     public void Visit(BThing bThing) { Result = new BTransformedThing(bThing, Arg); } 
     public void Visit(CThing cThing) { Result = new CTransformedThing(cThing, Arg); } 
     public void Visit(DThing dThing) { Result = new DTransformedThing(dThing, Arg); } 
    } 

    interface IThing {} 
    class Thing : IThing {} 
    class AThing : Thing {} 
    class BThing : Thing {} 
    class CThing : Thing {} 
    class DThing : Thing {} 
    class EThing : Thing { } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var things = new List<IThing> { new AThing(), new BThing(), new CThing(), new DThing(), new EThing() }; 
      var transformedThings = things.Select(thing => thing.GetTransformedThing(4)).Where(transformedThing => transformedThing != null).ToList(); 
      foreach (var transformedThing in transformedThings) 
      { 
       Console.WriteLine(transformedThing.GetType().ToString()); 
      } 
     } 
    } 
}