从app.config加载库

本文关键字:加载 config app | 更新日期: 2023-09-27 18:22:23

例如,我有很多计算数字平方根的方法。

一个开发者给了我他自己的.dll(maths1.dll),另一个开发者也给了我他的(maths2.dll),也许还有第三个(maths3.dll)。

它们都包含相同的类,实现相同的接口。

程序集1 Maths1.dll

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

程序集2Maths2.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文件中添加一行。

我需要控制台应用程序的Main的示例代码,向用户提供所有动态链接的.dll,并允许他使用所选库计算数字的平方根。

// 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加载程序集的任务。
详细的代码将不胜感激
谢谢

从app.config加载库

假设它们都实现了同一个接口(实际上是同一个,在同一个程序集中声明,而不仅仅是在单个命名空间中的同一定义),您可以使用依赖注入,如ms-unity,它可以在配置文件中管理,来注册该接口的所有实现,在运行时创建所有接口的具体实现,并执行它们。

编辑

编写了一个示例应用程序,我会在这里发布肉,并在上传时提供github或其他链接。

我在单独的程序集"UnityContainer.MasterImplementation"、"Satellite1.Implementation1"answers"Satellite 2.Implementation2"中有一个接口IMasterInterface和3个实现。UnityConfiguration是一个控制台应用程序,我使用NuGet引用了unity。为了方便起见,我已经将所有3个程序集的生成路径配置到同一个build目录中进行调试,因此控制台应用程序可以使用这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());
    

您可以使用反射来加载所选库并创建所需类型的实例。

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
}

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);