我正在使用WPF和C#构建一个应用程序,基本上我想允许任何人创建一个dll并将其放入文件夹中(类似于插件)。该应用程序将获取文件夹中的所有dll,加载它们并使用它们的方法(在接口中定义)。
有什么办法可以在运行时引用这些dll吗?还有更好的实现方式吗?
我已经实现了你所要求的功能,它可以在给定的目录中搜索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);
我认为你可以从类似以下的东西开始:
Assembly assembly = Assembly.LoadFrom("Something.dll");
Type type = assembly.GetType("SomeType");
object instanceOfSomeType = Activator.CreateInstance(type);
然后你可以使用它
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;
}
// 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" />
...
你需要一些东西来告诉你要实现哪种类型(也许是配置映射)。据我所知,接口只会提供一个合同,所有插件都要实现这个合同,以通过反射调用预期的方法。