我正在尝试为我的项目创建一个插件类型的archetecure。我希望能够加载程序集,获取从我的项目中的抽象基类派生的类型,实例化它并将该派生类型加载到主处理对象中。
我现在的问题是,当我从反射的程序集中实例化对象时,它始终为null。我觉得问题可能在于引用的程序集具有正在使用的第三方dll。这是代码:被击中的唯一例外是最后一个。
static void Main(string[] args)
{
string engineFilePath = ConfigurationManager.AppSettings["EngineFilesDirectory"]
+ "\\" + ConfigurationManager.AppSettings["EngineDllFileName"];
Assembly asm = Assembly.LoadFile(engineFilePath);
Type engineType = asm.GetType(ConfigurationManager.AppSettings["EngineType"]);
if (!engineType.IsSubclassOf(typeof(EngineConcrete)))
{
throw new ArgumentException("Engine is not derived from base implimentation.");
}
object engineInstance = asm.CreateInstance(engineType.Namespace + "." + engineType);
if (engineInstance == null)
{
//always thrown at this point
throw new Exception(string.Format("Engine object is null."));
}
return;
}
如果我将实例化行更改为Activator.CreateInstance(engineType)
,则会收到一条错误消息,指出无法找到反射程序集引用的第三方dll之一,尽管它们位于同一目录中。 dll被反映出来。
还有一个正在反映的类型的公共构造函数。它没有参数,并且继承自EngineConcrete
类。
答案 0 :(得分:1)
这是错误:engineType.Namespace + "." + engineType
- 此表达式的计算结果为"The.Namespace.The.Namespace.Type"
而不是"The.Namespace.Type"
。使用engineType.FullName
或Activator.CreateInstance
类并直接使用engineType
。
更新:请注意,MSDN说“...如果找不到typeName,则为null。”关于Assembly.CreateInstance
的返回值。
答案 1 :(得分:1)
我认为null是无法找到类型时得到的;命名空间名称加上类型名称可能不够(强命名问题)。如果将第三方dll放在正在执行的应用程序的目录中而不是插件的目录中会发生什么?
答案 2 :(得分:0)
问题是CLR没有找到第三方程序集,因为它们不在被探测的文件夹中。
您可以为AppDomain.CurrentDomain.AssemblyResolve事件添加事件处理程序来处理这些情况。下面是一个示例实现,适用于从bin文件夹中包含的“Plugins”文件夹动态加载程序集的示例:
class Program
{
static string _PluginDirectory;
static string PluginDirectory
{
get
{
if (_PluginDirectory == null)
{
_PluginDirectory = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), @"Plugins");
}
return _PluginDirectory;
}
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
AssemblyName assemblyName = new AssemblyName(args.Name);
return Assembly.LoadFile(System.IO.Path.Combine(PluginDirectory, assemblyName.Name + ".dll"));
}
static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
var asm = Assembly.LoadFile(System.IO.Path.Combine(PluginDirectory, @"Plugin.dll"));
var transmogrifier = asm.CreateInstance("Plugin.ConcreteTransmogrifier") as Common.Transmogrifier;
if (transmogrifier != null)
{
Console.WriteLine(transmogrifier.Transmogrify("Wowzers!"));
}
}
}