从字符串中加载类库中的winform

时间:2014-10-16 11:20:20

标签: c# winforms reflection class-library

基本上我有一个类库,其中包含了我编写的各种应用程序的大量“工具包”,然后通常引用此类库,然后创建一个空白的winforms应用程序并更改program.cs以创建工具包的实例需要。我想要做的是创建一个单独的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);

        }

首次尝试在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.

2 个答案:

答案 0 :(得分:1)

Assembly.GetType的{​​{3}}有一条说明:

  

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

答案 1 :(得分:1)

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