2009-04-17 19 views
12

私はクライアントアプリケーションとサーバーアプリケーションで使用されるクラスを持っています。 サーバーアプリケーションでは、クラストラフ拡張メソッドにいくつかの機能を追加します。よく働く。今すぐもう少し欲しいです:仮想拡張メソッド?

私のクラス(B)は別のクラス(A)から継承しています。

私は仮想関数をAに付けたいと思います(Execute()としましょう)。そしてその関数をBで実装しますが、サーバー内でのみ実装します。 Execute()メソッドは、サーバーだけが知っている型を使用して、サーバー上でしかできないものを行う必要があります。

BのようにAから継承する多くの型がありますが、それぞれに対してExecute()を実装したいと思います。

私は仮想拡張メソッドをAに追加できると思っていましたが、そのアイデアは飛ばされていないようです。私は、拡張メソッドの有無にかかわらず、この問題を解決する最もエレガントな方法を探しています。

答えて

4

いいえ、仮想拡張メソッドなどはありません。オーバーロードを使用することはできますが、多態性はサポートしていません。それはあなたが別のコード(依存性)を持つように依存性注入(など)のようなものを見てみたい場合がありますように聞こえる異なる環境で追加 - と定期的な仮想メソッドでそれを使用します。

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

次に提供するために、DIフレームワークを使用しますサーバー固有のISomeUtilityを実行時にBに実装します。

+0

おかげでマルク。私はこのようなものを実装します。私はこれらのクラスをシリアル化し、サーバーからクライアントへ、そしてバックでワイヤを介して送信しています。だから伝統的なDIはややこしいかもしれませんが、私はクラスB(おそらくBを継承しています)の同等のサーバサイドを実装でき、クライアントがBのインスタンスをサーバに送信すると、 ServerBの新しいインスタンス – Lucas

+0

レジストリアプローチは、シリアライゼーションで正常に機能します。私はWCFオブジェクトとのアセンブリ共有を行うためにこのアプローチを使用しています... –

0
;

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

(プラスサーバー上で、ISomeUtility実装を登録あなたはRegistryなどを記述する必要があるだろう):あなたは、中央staticレジストリ(IOC、ないDI)と同じことを行うことができます

仮想はOOPのやり方で継承を意味し、拡張メソッドはコンパイラが最初のパラメータの型のインスタンスを呼び出すふりをすることを可能にする構文的な砂糖を少しだけ使って "ちょうど"静的なメソッドです。そうではありません、仮想拡張メソッドは問題外です。

Marc Gravellの回答を参照して問題を解決してください。

0

サービスレジスタを実装できます。例(サーバー側):

static IDictionary<Type, IService> serviceRegister; 

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

必要なのは、拡張メソッドではなく、サーバー側の機能を実装するサーバーのサービスです。私は多くのロジックを拡張メソッドに入れません。

0

私は、あなたのビジネスドメインに従って構造化されたAから継承したクラス階層を持っていることを確認してください。次に、クラスの実行場所に応じて動作を追加します。これまでは拡張メソッドを使用していましたが、今ではクラス階層でそれらを変更することはできません。サーバーでどのような動作をしていますか?

トランザクション管理やセキュリティのようなものであれば、依存性注入のMarcの提案によって実装されたポリシーはうまくいくはずです。より限定されたバージョンのDIについては、Strategy patternをデリゲートとラムダを使用して実装することも検討できます。しかし、明確ではないことは、クライアントコードが現在クラスとその拡張メソッドをサーバ上でどのように使用しているかです。サーバー側の機能をどのように追加するかについて、他のクラスはどのように依存していますか?彼らは現在、拡張メソッドを見つけることを期待しているサーバーサイドクラスのみですか?

いずれにしても、2つの次元(継承階層、実行環境)に沿ってバリエーションを導入しているため、慎重なテスト容易性設計とテスト戦略が必要なようです。あなたはユニットテストを使用しています、私は信頼していますか?選択したソリューション(例:構成を通じて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()); 
      } 
     } 
    } 
} 
+1

私はこの例が気に入っていますが、あなたはあなたのポイントをはるかにsiplerに置くことができました。 –