从字符串从类库加载winform
本文关键字:winform 加载 类库 字符串 | 更新日期: 2023-09-27 18:26:40
基本上,我有一个类库,其中包含许多我编写的各种应用程序的"toolkit",然后我通常引用这个类库,然后创建一个空白的winforms应用程序,并更改program.cs以创建所需toolkit的实例。我想做的是创建一个exe,它可以根据参数或设置xml文件运行所有工具包(这不是问题所在)问题是从字符串的不同库创建一个类的实例。我想问的是,这可能吗?到目前为止我尝试了什么:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Advent.GlobalSettings.TestEnvironment = false;
string namespaceName = "GlobalLib.Toolkits.XmlService.Main";
//first attempt
Assembly ass = Assembly.GetExecutingAssembly();
Type CAType = ass.GetType(namespaceName);
var myObj = Activator.CreateInstance(CAType);
Form nextForm2 = (Form)myObj;
//second attempt
var t = Assembly
.GetExecutingAssembly()
.GetReferencedAssemblies()
.Select(x => Assembly.Load(x))
.SelectMany(x => x.GetTypes()).First(x => x.FullName == namespaceName);
var myObj2 = Activator.CreateInstance(t);
Application.Run((Form) myObj2);
}
第一次尝试在var myObj = Activator.CreateInstance(CAType);
返回Value cannot be null.
第二次尝试返回Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
Assembly.GetType
的文档中有一条注释,上面写着:
若要在其他程序集中搜索某个类型,请使用type.GetType(String)方法重载,该重载可以选择性地将程序集显示名称作为类型名称的一部分。
由于要加载的类型在不同的程序集中,因此应按照建议切换到Type.GetType(String)
。您还需要调整namespaceName
变量,以便在格式中包含程序集名称
"namespace.class, assemblyname"
你的代码需要是这样的:
//I've had a stab in the dark at your assembly name
//the bit after the comma could be wrong
string namespaceName = "GlobalLib.Toolkits.XmlService.Main, GlobalLib.Toolkits";
Type CAType = Type.GetType(namespaceName);
var myObj = Activator.CreateInstance(CAType);
Form nextForm2 = (Form)myObj;
听起来像是经典的依赖项注入问题。但是,如果您想跳过依赖项注入容器开销,您可以模仿MEF的行为,即从文件夹加载引用。在我看来,使用GetReferencedAssemblies()
是个坏主意,因为它也会搜索所有引用的.NET程序集、System、System.Windows.Forms等…
string companyFolder = @"<folder with assemblies>";
string fullClassName= @"<desired form fully qualified type name>";
var di = new DirectoryInfo(companyFolder);
// include forms in form apps too
var referenceAssemblyFiles = di.GetFiles("*.dll").Union(di.GetFiles("*.exe"));
var types = referenceAssemblyFiles
.Select(x => Assembly.LoadFile(x.FullName))
.SelectMany(x => x.GetTypes())
.ToList();
// might also check respective type is a form
var t = types.FirstOrDefault(x => x.FullName == fullClassName);
object myFormObj = null;
if (t != null)
{
myFormObj = Activator.CreateInstance(t);
Application.Run((Form)myFormObj);
}