12

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

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

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

B と同じように A から継承する型はたくさんあるので、それぞれに Execute() を実装したいと思います。

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

4

6 に答える 6

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実装を登録します)

于 2009-04-17T07:59:07.517 に答える
4

新しい動的型機能を使用すると、型のレジストリをメソッドに構築する必要がなくなります。

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());
            }
        }
    }
}
于 2011-02-11T18:49:41.167 に答える
0

Virtualは、OOP方式での継承を意味し、拡張メソッドは「単なる」静的メソッドであり、少し構文的な糖衣構文を使用して、コンパイラーが最初のパラメーターのタイプのインスタンスを呼び出すふりをすることができます。したがって、仮想拡張メソッドは問題外です。

問題の可能な解決策については、MarcGravellによる回答を確認してください。

于 2009-04-17T08:05:05.287 に答える
0

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

static IDictionary<Type, IService> serviceRegister;

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

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

于 2009-04-17T08:08:47.947 に答える
0

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

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

いずれにせよ、2 つの同時ディメンション (継承階層、実行環境) に沿ってバリエーションを導入しているため、慎重なテスト容易性の設計とテスト戦略が必要になるようです。あなたは単体テストを使用していますね。選択したソリューション (構成による DI など) が、テストやモックとうまく相互作用することを確認してください。

于 2009-04-17T08:39:40.633 に答える