1

たとえば、数値の平方根を計算する方法がたくさんあるとします。

ある開発者は自分の.dll (maths1.dll) をくれ、別の開発者は自分の .dll (maths2.dll) をくれて、3 番目の開発者 (maths3.dll) もくれます。

それらはすべて同じクラスを含み、同じインターフェースを実装しています。

アセンブリ 1 Maths1.dll

public class Maths : IMaths {
    public static string Author = "Author1";
    public static SquareRoot(int number) {
        // Implementation method 1
    }
}

アセンブリ 2 Maths2.dll

public class Maths : IMaths {
    public static string Author = "Author2";
    public static SquareRoot(int number) {
        // Implementation method 2
    }
}

などなど

そして、実行時にすべてのdllを動的に認識しなければならないコンソールアプリケーションがあります。

コード内で .dll ファイルを探すのは望ましくありません。

// DON'T WANT THIS
DirectoryInfo di = new DirectoryInfo("bin");
FileInfo[] fi = di.GetFiles("*.dll");

私の考えは、カスタム構成セクションを使用してapp.configファイルからそれらを管理することです。

<configuration>

    <configSections>
        <section name="MathsLibraries" type="MyMathsLibrariesSectionClass, ApplicationAssembly" />
    </configSections>

    <MathsLibraries>
        <Library author="Author1" type="MathsClass, Maths1Assembly" /><!-- Maths1.dll -->
        <Library author="Author2" type="MathsClass, Maths2Assembly" /><!-- Maths2.dll -->
        <Library author="Author3" type="MathsClass, Maths3Assembly" /><!-- Maths3.dll -->
    </MathsLibraries>

</configuration>

ライブラリ ファイルMaths1.dllをアプリケーションのbinフォルダーに手動でコピーすることを考慮して、 MathsLibrariesセクションのapp.configファイルに行を追加するだけです。

動的にリンクされたすべての .dll をユーザーに提示し、選択したライブラリを使用して数値の平方根を計算できるようにする、コンソール アプリケーションのMainのサンプル コードが必要です。

// NOT WORKING CODE, JUST IDEA OF WHAT IS NEEDED
public static void Main(string[] args) {

    // Show the user the linked libraries
    MathsLibraries libs = MathsLibraries.GetSection();
    Console.WriteLine("Available libraries:");
    foreach (MathLibrary lib in libs.Libraries) {
        Console.WriteLine(lib.Author);
    }

    // Ask for the library to use
    Console.Write("Which do you want to use?");
    selected_option = Console.Read();

    IMaths selected_library;
    // since we don't know wich class would be,
    // declare a variable using the interface we know they al implement.

    // Assign the right class to the variable
    if (selected_option == '1') {
        selected_library = Assembly1.Maths;    
    } else if (selected_option == '2') {
        selected_library = Assembly2.Maths;
    }
    // other options...

    // Invoke the SquareRoot method of the dynamically loaded class
    float sqr_result = selected_library.SquareRoot(100);
    Console.WriteLine("Result is {0}", sqr_result);

    Console.WriteLine("Press Enter key to exit");
    Console.Read();
}

app.config からアセンブリをロードするこのタスクで誰か助けてください。
詳細なコードをいただければ幸いです。
ありがとう!

4

3 に答える 3

1

それらがすべて同じインターフェイスを実装していると仮定すると (実際には、個々の名前空間で同じ定義だけでなく、同じアセンブリで宣言された同じもの)、構成ファイルで管理できる ms unity のような依存性注入を使用して、すべての実装を登録できます。実行時にすべての具体的な実装を作成し、実行します。

編集

サンプルアプリを書きました。肉をここに投稿し、アップロードしたらgitハブなどへのリンクを提供します。

インターフェイス、IMasterInterface、および個別のアセンブリ「UnityContainer.MasterImplementation」、「Satellite1.Implementation1」、および「Satellite2.Implementation2」に 3 つの実装があります。UnityConfiguration はコンソール アプリであり、NuGet を使用して Unity を参照しました。便宜上、3 つのアセンブリすべてのビルド パスをデバッグ用の同じビルド ディレクトリに構成したので、コンソール アプリで 2 つのサテライト アセンブリを使用できます。

IMasterInterface には、単一のメソッド GetResult(): string があります。

  1. 次のように Web 構成を編集します。

    
        <configuration>
            <configSections>
                <section name="unity"
                   type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
                         Microsoft.Practices.Unity.Configuration, Version=3.0.0.0,
                         Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
            </configSections>
            <unity>
                <typeAliases>
                    <typeAlias alias="IMasterInterface"           type="UnityInjection.IMasterInterface, UnityInjection" />
                    <typeAlias alias="MasterImp"                  type="UnityInjection.MasterImplementation, UnityInjection" />
                    <typeAlias alias="SatelliteOneImplementation" type="Satellite1.Implementation1, Satellite1" />
                    <typeAlias alias="SatelliteTwoImplementation" type="Satellite2.Implementation2, Satellite2" />
                </typeAliases>
                <containers>
                    <container name="containerOne">
                        <types>
                            <type type="IMasterInterface" mapTo="MasterImp" name="Master" />
                            <type type="IMasterInterface" mapTo="SatelliteOneImplementation" name="One" />
                            <type type="IMasterInterface" mapTo="SatelliteTwoImplementation" name="Two" />
                        </types>
                    </container>
                </containers>
            </unity>
        </configuration>
    
  2. コンテナーを構成する

    
        //Set up the dependency container
        IUnityContainer myContainer = new UnityContainer();
        var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
        section.Configure(myContainer, "containerOne");
    
  3. すべての実装を解決

    
        //create all implementations of out interface
        var implementations = myContainer.ResolveAll<IMasterInterface>();
    
    
    //call the method we are interested in for all implementations
    foreach (var implementation in implementations)
    {
        Console.WriteLine(implementation.GetResult());
    }
    
  4. 特定の名前付き実装を解決する

    
        //Get a particular one
        var specific = myContainer.Resolve<IMasterInterface>("Master");
        Console.WriteLine(specific.GetResult());
    
于 2013-07-13T12:19:23.457 に答える
0

C# - アセンブリをロードし、クラスを検索し、Run() メソッドを呼び出す正しい方法の重複の可能性

    var asm = Assembly.LoadFile(@"YourMathAssembly.dll");
   var type = asm.GetType("Maths");
     var sqrRoot = Activator.CreateInstance(Maths) as IMaths;
 if (sqrRoot == null) 
    throw new Exception("broke");
        sqrRoot .SquareRoot(100);
于 2013-07-13T12:13:34.953 に答える
0

リフレクションを使用して、選択したライブラリをロードし、必要なタイプのインスタンスを作成できます。

var assembly = Assembly.LoadFrom("selected_math_library.dll");
var types = assembly.GetTypes();

var mathType = (from type in types
                      where type.GetInterface("IMath") != null && !type.IsAbstract
                      select type).ToList();

if (mathType.Count > 0)
{
    IMath math = (IMath)Activator.CreateInstance(mathType);
    // call methods from math

}
于 2013-07-13T12:15:22.793 に答える