比如说,我有很多计算数字平方根的方法。
一位开发人员给了他自己的 .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
}
}
汇编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 文件。
我需要控制台应用程序的 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加载程序集的任务 详细的代码将不胜感激 谢谢!
答案 0 :(得分:0)
C# - Correct Way to Load Assembly, Find Class and Call Run() Method
可能重复 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);
答案 1 :(得分: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
}
答案 2 :(得分:0)
假设它们都实现了相同的接口(实际上是相同的接口,在同一个程序集中声明,而不仅仅是各个名称空间中的相同定义),您可以使用依赖注入,如ms unity,可以在配置文件中管理,注册此接口的所有实现,在运行时创建所有实现,并执行它们。
修改
写了一个示例应用程序,我会在这里发布这些内容,当我上传它时会提供git hub的链接。
我在单独的程序集“UnityContainer.MasterImplementation”,“Satellite1.Implementation1”和“Satellite2.Implementation2”中有一个接口,IMasterInterface和3个实现。 UnityConfiguration是一个控制台应用程序,我使用NuGet引用了unity。为方便起见,我已将所有3个程序集的构建路径配置到Debug的同一Build目录中,因此控制台应用程序可以使用2个附属程序集。
IMasterInterface有一个方法GetResult():string。
使用以下内容编辑网络配置:
<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>
配置容器
//Set up the dependency container
IUnityContainer myContainer = new UnityContainer();
var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Configure(myContainer, "containerOne");
解决所有实施
//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());
}
解析特定的命名实现
//call the method we are interested in for all implementations
foreach (var implementation in implementations)
{
Console.WriteLine(implementation.GetResult());
}