从字符串从类库加载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.

从字符串从类库加载winform

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);
      }