-1

アプリで依存性注入を使用することはありません。依存性注入に関するいくつかの記事を読んだところ、その概念は興味深いものでしたが、実際に実装するのは難しいと思いました。今、win フォーム アプリに依存性注入を実装したいと考えています。

当社は現在、UPS、Fedex、Purolator などの多くの運送会社と協力していますが、将来的には他の多くの運送会社と協力する予定です。UPS、Fedex、Purolator などのすべての運送会社向けに個別のクラス ライブラリ プロジェクトを開発し、それらの dll をメイン フォーム アプリに含めました。問題は、多くの場合、国コードなどのコードにいくつかのことをハードコーディングすることです.

たとえば、4 つのボタンがあるフォームが 1 つあります。これらのボタンのように、「Ship with UPS WorldShip」、「Ship with UPS WebAPI」という別のボタン、「Ship with FedEX Desktop Apps」という別のボタン、「Ship with Fedex WebAPI」という最後のボタンがあります。

ユーザーが UPS WorldShip ボタンをクリックすると、フォルダにフラット ファイルが生成されます。ユーザーが UPS WebAPI ボタン​​をクリックすると、UPS サイトにリクエストが送信されます。

ユーザーが FedEX WinApps ボタンをクリックすると、フォルダにフラット ファイルが生成されます。ユーザーが FedEX WebAPI ボタン​​をクリックすると、要求が FedEx サイトに送られます。

したがって、ユーザーが任意のボタンをクリックすると、dll に存在する特定の関数を呼び出してタスクを完了します。

私の最後ではすべてが正常に機能していますが、問題は、当社が別の新しい運送会社と協力し始めたときに、その会社用に別のクラス ライブラリを作成する必要があることです。

アプリで DI を使用したことはなく、経験もないと言いました。そのため、新しい海運会社が参加するときにDIを使用して自分の状況をどのように処理できるかを教えてくれる人がいれば、余分なコードを書く必要はありません。アプリに DI を実装する方法を教えてください。また、ガイダンス用のサンプル DI コードを使用して状況を処理する方法も教えてください。

私の第二段階の質問

1) InitializeKernel() 関数を呼び出す必要がある場合 アプリケーションのロード時またはフォームのロード時

2)私はninjectに慣れていないので、このコード行の意味がわかりません

.Configure((b, c) => b.InTransientScope().Named(c.Name));

3) c.Name は何を返しますか?

4) 構成ファイルのエントリが見つかりませんでした。ninject は unity DI のような構成ファイルのエントリを必要としませんか?

あなたが与えたコードは非常にプロフェッショナルに見えます。可能であれば、私のすべてのポイントに答えてください。

最後に、DI と ninject コードの使用法を学習するために ninject で利用できる PDF があるか教えてください。

ありがとう

私の質問の第3段階

申し訳ありませんが、InitializeKernel() は一度宣言してください。

あなたは、Ninjectが流暢な構成をサポートするだけだと言いました。新しい運送会社が参加すると、このブロックのコードを

using(var kernel = InitializeKernel())     
{
    // 4.1 resolve delivery services by names
    var upsWorldShip = kernel.Get<IShippingCompanyService>("ShippingUpsWorldShip");
    var fedExDesktopApps = kernel.Get<IShippingCompanyService>("ShippingFedExDesktopApps");


    var PurolatorExDesktopApps = kernel.Get<IShippingCompanyService>("PurolatorFedExDesktopApps");

    // 4.2 delivery processing
    upsWorldShip.Delivery();
    fedExDesktopApps.Delivery();

    // 5 PROFIT!
}

だからここにこの行を追加する必要があります

var PurolatorExDesktopApps = kernel.Get<IShippingCompanyService>  ("PurolatorFedExDesktopApps");

問題は、新しい出荷関連の dll が追加されるたびに、上記のブロックに 1 行のコードを追加する必要があることです....これは望ましくありません。

すべてのdllの関連情報を構成ファイルに追加し、そこからすべてのdllからクラス化されたすべてをロードしてインスタンス化できれば、より良いでしょう。だから私はあなたの提案を探しています。ありがとう

4

2 に答える 2

2

Configuration by Conventionを求めているようです。これは、共通の構成を共有する必要があるコンポーネントのグループを特定し、その構成を 1 つのステートメントで指定することを意味します

実際には、これは、選択した機能「配信」を持つすべてのライブラリをプロジェクトの「特別な」場所にデプロイし、「特別な」インターフェースからすべての実装を継承することを意味します。最後に、DI コンテナーを作成してそれらを見つけ、すべてを構成します。

規則の定義

を使用してこれを実現する簡単な例を次に示しますNinject.Extensions.Conventions

コメントに注意

// 1 define "delivery" interface
interface IShippingCompanyService
{
    void Delivery();
}

// 2.1 — first assembly "Ups.Services.dll"
public class ShippingUpsWorldShip : IShippingCompanyService
{
    public void Delivery()
    {
        "Ship with UPS WorldShip".Dump();
    }
}

// 2.2 — first assembly "FedEx.Services.dll"
public class ShippingFedExDesktopApps : IShippingCompanyService
{
    public void Delivery()
    {
        "Ship with FedEX Desktop Apps".Dump();
    }
}

構成の定義

Ninject Kernel を使用して構成を構築します (StandardKernelこの場合)

// 3 kernel configuration
public static IKernel InitializeKernel() 
{ 
    var kernel = new StandardKernel();

    kernel.Bind(x => x
         // 3.1 search in current assembly
        .FromThisAssembly()
            .SelectAllClasses() // 3.2 select all classes implement "special" interface
            .InheritedFrom<IShippingCompanyService>()
        // 3.3 search all assemblies by wildcards
        .Join.FromAssembliesMatching("./*Services.dll")
            .SelectAllClasses() // 3.2 select all classes implement special interface
            .InheritedFrom<IShippingCompanyService>()
        // 3.4 bind to "special" interface
        .BindAllInterfaces()
        // 3.5 configure lifetime management and dependency name
        .Configure((b, c) => 
            b.InTransientScope().Named(c.Name)));

    return kernel; 
} 

依存関係を解決する方法

アプリケーションの構成ルートから、配信サービスを名前で解決します

// 4 from your Compositon Root ...
using(var kernel = InitializeKernel())     
{
    // 4.1 resolve delivery services by names
    var upsWorldShip = kernel.Get<IShippingCompanyService>("ShippingUpsWorldShip");
    var fedExDesktopApps = kernel.Get<IShippingCompanyService>("ShippingFedExDesktopApps");

    // 4.2 delivery processing
    upsWorldShip.Delivery();
    fedExDesktopApps.Delivery();

    // 5 PROFIT!
}

ここで利用可能なすべてのソース

概要

規約による構成は、多くのプロジェクトですでに採用されている非常に役立つアプローチです。とはいえ、Mark Seemann の著書「Dependency Injection in .NET」を読んで、規則に関する彼の講演を視聴することをお勧めします。

回答

  1. InitializeKernel() 関数を呼び出す必要があるのはいつですか? アプリケーションのロード時またはフォームのロード時
  2. 私はninjectに慣れていないので、このコード行の意味がわかりません:.Configure((b, c) => b.InTransientScope().Named(c.Name)))
    • 依存関係が注入されるたびに、新しいインスタンスが作成されます
    • 依存関係はクラス名で参照できます
  3. c.Nameが返ってきますか?
    • クラス名
  4. 構成ファイルのエントリが見つかりませんでした。ninject は unity DI のような構成ファイルのエントリを必要としませんか?
    • Ninject は流暢な構成のみをサポートします
  5. InitializeKernel()2番目と呼ばれる同じ名前を持つ2つのメソッドを宣言するのInitializeKernel()は何のためですか?
    • メソッドの宣言は 1 つだけです。InitializeKernel()
  6. 最後に、DI と ninject コードの使用法を学習するために ninject で利用できる PDF があるか教えてください。
于 2013-01-10T14:46:23.283 に答える
1

まず、Seemann による非常に優れた本「Dependency Injection in .NET」があります。

そして、これ多くの DI コンテナーのベンチマークです。

DI の主な考え方は、消費者が消費するサービスのインスタンスを作成してはならないということです。
そして、各サービスは、最も抽象的な方法でクライアントに提示する必要があります:インターフェース/基本クラス(あなたの場合、それはその特別な機能です)。

次に、その会社用に別のクラス ライブラリを作成する必要があります。

それは避けられません。この新しい API をどのように参照するかは重要です。クライアント コードは、実装の詳細を認識しないようにする必要があります。

于 2013-01-10T13:18:40.187 に答える