我正在使用WPF和C#构建应用程序,基本上我想允许任何人创建一个dll并将其放入一个文件夹(类似于插件)。应用程序将获取文件夹上的所有dll,加载它们并使用它们的方法(在接口上定义)。
如何在运行时引用dll的任何想法?更好的想法如何实现这个?
答案 0 :(得分:10)
我已经实现了类似于您要求通过给定目录中的dll搜索并找到实现特定接口的类的内容。以下是我以前用过的课程:
public class PlugInFactory<T>
{
public T CreatePlugin(string path)
{
foreach (string file in Directory.GetFiles(path, "*.dll"))
{
foreach (Type assemblyType in Assembly.LoadFrom(file).GetTypes())
{
Type interfaceType = assemblyType.GetInterface(typeof(T).FullName);
if (interfaceType != null)
{
return (T)Activator.CreateInstance(assemblyType);
}
}
}
return default(T);
}
}
你所要做的就是用这样的东西初始化这个类:
PlugInFactory<InterfaceToSearchFor> loader = new PlugInFactory<InterfaceToSearchFor>();
InterfaceToSearchFor instanceOfInterface = loader.CreatePlugin(AppDomain.CurrentDomain.BaseDirectory);
如果此答案或任何其他答案可帮助您解决问题,请单击复选标记将其标记为答案。此外,如果您觉得这是一个很好的解决方案,请表达您的赞赏。我以为我会提到它,因为看起来你没有接受任何其他问题的答案。
答案 1 :(得分:1)
看看MEF。它应该提供你正在寻找的东西。
使用reflection也是一种选择,但如果你问我,MEF将是更好的选择。
答案 2 :(得分:1)
我认为你可以从像
这样的东西开始Assembly assembly = Assembly.LoadFrom("Something.dll");
Type type = assembly.GetType("SomeType");
object instanceOfSomeType = Activator.CreateInstance(type);
然后你可以使用它
答案 3 :(得分:0)
string relative = "ClassLibrary1.dll";
string absolute = Path.GetFullPath(relative);
Assembly assembly = Assembly.LoadFile(absolute);
System.Type assemblytype = assembly.GetType("ClassLibrary1.Class1");
object []argtoppass={1,2};
var a =Activator.CreateInstance(assemblytype, argtoppass);
System.Type type = a.GetType();
if (type != null)
{
string methodName = "add";
MethodInfo methodInfo = type.GetMethod(methodName);
object result = methodInfo.Invoke(a, null);
int a1 = (int )result;
}
答案 4 :(得分:0)
我正在开发类似的东西,其中客户可能安装了不同版本的第三方DLL,但名称和位置相同。如果我们没有引用正确的版本,我们就会失败。我使用反射来识别版本,但我需要修改设置以根据版本使用不同的DAL类,或者通过接口使DAL版本独立。
我倾向于第二个。如果您在代码中创建一个“虚拟DLL”,它实现了一个接口,该接口具有您想要从目标程序集调用的所有方法,并且不是将实际类型作为参数传递给接口,那么您应该能够使用所有您的设计时代码中的方法和基于模型实现的编译,甚至进行测试,但是当您在运行时加载实际的程序集时,从实际程序集中获取结果。 如果这对你有用,请告诉我,我也会告诉你。
Joey Morgan
答案 5 :(得分:0)
上面的答案几乎可以满足您的需求。您可以尝试在程序启动时加载要插入到应用程序中的所有dll:
// note: your path may differ, this one assumes plugins directory where exe is executed
var pluginsDirectory = Path.Combine(AppContext.BaseDirectory, "plugins");
if (Directory.Exists(pluginsDirectory))
{
var dllPaths = Directory.GetFiles(pluginsDirectory);
if (dllPaths.Count() > 0)
{
foreach (var dllPath in dllPaths)
{
Assembly.LoadFrom(Path.Combine("plugins", Path.GetFileName(dllPath)));
}
}
else
{
// warn about no dlls
}
}
else
{
// warn about no plugins directory
}
如何引用dll及其类型:
// if dll file name is My.Plugin.Assembly.ShortName.dll, then reference as follows
var pluginAssembly = Assembly.Load("My.Plugin.Assembly.ShortName");
var typesInAssembly = pluginAssembly.GetExportedTypes();
var instanceType = typesInAssembly.FirstOrDefault(t => t.Name == "MyClassName");
var instance = Activator.CreateInstance(instanceType, new object[] { "constructorParam1", "constructorParam2" });
instanceType.InvokeMember("MyMethod", BindingFlags.InvokeMethod, null, instance, new object[] { "methodParam1", "methodParam2" });
您可能需要告诉您的应用配置以探测您的插件目录。我假设插件的一个子目录,您可以探查子目录路径的列表。
...
<runtime>
<assemblyBinding ...
<probing privatePath="plugins" />
...
您将需要一些信息来告诉您要实现哪种类型(也许是配置映射)。据我所知,该接口将仅提供所有插件实现的合同,以提供通过反射调用的预期方法。