【问题标题】:Load winform from class library from string从字符串从类库加载winform
【发布时间】:2014-12-11 17:51:29
【问题描述】:

基本上我有一个类库,其中包含我编写的各种应用程序的大量“工具包”,然后我通常引用这个类库然后创建一个空白的 winforms 应用程序并更改 program.cs 以创建工具包的实例必需的。我想做的是创建一个可以根据参数或设置xml文件运行所有工具包的单个exe(这不是问题)问题是从字符串中的不同库创建类的实例。我要问的是,这可能吗?到目前为止我尝试了什么:

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

        }

第一次尝试返回Value cannot be null.var myObj = Activator.CreateInstance(CAType); 第二次尝试返回Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.

【问题讨论】:

  • 您的表单类的名称是什么?是“主要”吗?
  • 是的,它是“Main”命名空间 'GlobalLib.Toolkits.XmlService{public partial class Main : Form{ ...' 请记住这是一个参考库
  • 你可以试试AppDomain.CurrentDomain.GetAssemblies()而不是Assembly.GetExecutingAssembly()。这将为您提供当前加载到 appdomain 中的所有程序集。但是您第二次尝试的例外情况为您提供了有关为什么无法实例化该类型的信息,请查看它所说的内容。
  • @Houlahan:在您的第一次尝试中,ass.GetType() 返回 null,对吧?

标签: c# winforms reflection class-library


【解决方案1】:

Assembly.GetTypedocumentation 上面有一条说明:

要在其他程序集中搜索类型,请使用 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;

【讨论】:

    【解决方案2】:

    听起来像是经典的依赖注入问题。但是,如果您想跳过依赖注入容器开销,您可能会模仿 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);
          }
    

    【讨论】:

      猜你喜欢
      • 2011-06-23
      • 2017-03-14
      • 1970-01-01
      • 2013-06-20
      • 1970-01-01
      • 1970-01-01
      • 2011-09-11
      • 2023-03-28
      • 1970-01-01
      相关资源
      最近更新 更多