C# 使用Assembly.Load创建外部项目的新WinForm

C# 使用Assembly.Load创建外部项目的新WinForm,c#,winforms,assembly.load,C#,Winforms,Assembly.load,我在C#中有两个windowsForm项目(项目A和B),但我想在项目B中添加对项目A的代码引用,并从项目B中调用项目A。 我使用了Assembly.Load,只有删除了主要的void参数,它才起作用 项目A的窗体应作为项目B的父级打开 我尝试使用Assembly.load和activator.createinstance,但当我尝试传递方法参数时,它不起作用 使用参数参数时,返回错误 (System.MissingMethodException:'类型中的构造函数' CompareXMLToo

我在C#中有两个windowsForm项目(项目A和B),但我想在项目B中添加对项目A的代码引用,并从项目B中调用项目A。 我使用了Assembly.Load,只有删除了主要的void参数,它才起作用

项目A的窗体应作为项目B的父级打开

我尝试使用Assembly.load和activator.createinstance,但当我尝试传递方法参数时,它不起作用

使用参数参数时,返回错误 (System.MissingMethodException:'类型中的构造函数' CompareXMLTools.Main“未找到”。)

项目A Program.cs

namespace CompareXMLTools
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Main(args));

        }
    }
}
项目B

注意:只有当我从Main方法中删除**
string[]args
**字段时,Project B命令才起作用


调用项目A的新WinForm时,我需要传递参数,如何才能做到这一点?

我建议在Form1中添加一个无参数构造函数,这样您就可以从外部程序集调用它,该程序集可能不知道它需要多少参数(如果有),并添加处理
null
参数所需的逻辑

namespace XMLValidator
{
    public partial class Main : Form
    {
        public Main() : this(null) { }

        public Main(string[] args) {
            InitializeComponent();
            [Something] = args;
        }
    }
}
在此之后,如果您不想/不能使用接口(为了对这些程序集之间的契约有一个共同的理解),您必须依赖于您对要加载的表单的了解,并通过
Name
调用它们

可以使用重载传递参数,该重载接受一个类型(您知道要加载的类型,一个表单)和
params object[]
形式的参数

public static object CreateInstance (Type type, params object[] args);
params
中的每个对象表示指定类的构造函数所期望的参数。
无参数构造函数不需要任何参数,因此在
args[0]
中传递
null
否则,
args[0]
包含要调用的非空构造函数的参数,以初始化指定的类

object[] args = new object[1] { new string[] { "Args String", "Args Value", "Other args" } };
并致电:

Activator.CreateInstance([Type], args) as [Type];
我建议构建一个处理外部程序集初始化的中间类,自动提取一些有用的信息(命名空间、特定类型的资源、表单、项目资源等)。因此,您只需提供表单的名称即可激活并显示它

例如,从父窗体中的菜单:

public partial class MDIParent : Form
{
    private ResourceBag formResources = null;

    public MDIParent()
    {
        InitializeComponent();
        formResources = new ResourceBag([Assembly Path]);
    }

    // [...]

    // From a ToolStrip MenuItem, load with arguments
    private void loadExternalFormToolStripMenuItem_Click(object sender, EventArgs e)
    {
        object[] args = new object[1] { new string[] { "Args String", "Args Value", "Other args" } };
        Form form1 = formResources.LoadForm("Form1", args);
        form1.MdiParent = this;
        form1.Show();
    }

    // From another ToolStrip MenuItem, load using the default Constructor
    private void loadExternalFormNoParamsToolStripMenuItem_Click(object sender, EventArgs e)
    {
        Form form1 = formResources.LoadForm("Form1");
        form1.MdiParent = this;
        form1.Show();
    }

}
ResourceBag
助手类

如果要加载不属于默认
命名空间的类对象,可以向
公共表单LoadForm()
添加重载,以传递不同的
命名空间

using System.IO;
using System.Reflection;
using System.Windows.Forms;

internal class ResourceBag
{
    private string m_AssemblyName = string.Empty;
    private static Assembly asm = null;

    public ResourceBag() : this(null) { }

    public ResourceBag(string assemblyPath)
    {
        if (!string.IsNullOrEmpty(assemblyPath)) {
            this.AssemblyName = assemblyPath;
        }
    }

    public string NameSpace { get; set; }

    public string AssemblyName {
        get => m_AssemblyName;
        set {
            if (File.Exists(value)) {
                m_AssemblyName = value;
                asm = Assembly.LoadFrom(m_AssemblyName);
                this.NameSpace= asm.GetName().Name;
            }
            else {
                throw new ArgumentException("Invalid Assembly path");
            }
        }
    }

    public Form LoadForm(string formName, params object[] args)
    {
        if (asm == null) throw new BadImageFormatException("Resource Library not loaded");
        return Activator.CreateInstance(asm.GetType($"{NameSpace}.{formName}"), args) as Form;
    }
}

我建议在Form1中添加一个无参数构造函数,这样您就可以从一个可能不知道需要多少参数(如果有)的外部程序集中调用它,并添加处理
null
参数所需的逻辑

namespace XMLValidator
{
    public partial class Main : Form
    {
        public Main() : this(null) { }

        public Main(string[] args) {
            InitializeComponent();
            [Something] = args;
        }
    }
}
在此之后,如果您不想/不能使用接口(为了对这些程序集之间的契约有一个共同的理解),您必须依赖于您对要加载的表单的了解,并通过
Name
调用它们

可以使用重载传递参数,该重载接受一个类型(您知道要加载的类型,一个表单)和
params object[]
形式的参数

public static object CreateInstance (Type type, params object[] args);
params
中的每个对象表示指定类的构造函数所期望的参数。
无参数构造函数不需要任何参数,因此在
args[0]
中传递
null
否则,
args[0]
包含要调用的非空构造函数的参数,以初始化指定的类

object[] args = new object[1] { new string[] { "Args String", "Args Value", "Other args" } };
并致电:

Activator.CreateInstance([Type], args) as [Type];
我建议构建一个处理外部程序集初始化的中间类,自动提取一些有用的信息(命名空间、特定类型的资源、表单、项目资源等)。因此,您只需提供表单的名称即可激活并显示它

例如,从父窗体中的菜单:

public partial class MDIParent : Form
{
    private ResourceBag formResources = null;

    public MDIParent()
    {
        InitializeComponent();
        formResources = new ResourceBag([Assembly Path]);
    }

    // [...]

    // From a ToolStrip MenuItem, load with arguments
    private void loadExternalFormToolStripMenuItem_Click(object sender, EventArgs e)
    {
        object[] args = new object[1] { new string[] { "Args String", "Args Value", "Other args" } };
        Form form1 = formResources.LoadForm("Form1", args);
        form1.MdiParent = this;
        form1.Show();
    }

    // From another ToolStrip MenuItem, load using the default Constructor
    private void loadExternalFormNoParamsToolStripMenuItem_Click(object sender, EventArgs e)
    {
        Form form1 = formResources.LoadForm("Form1");
        form1.MdiParent = this;
        form1.Show();
    }

}
ResourceBag
助手类

如果要加载不属于默认
命名空间的类对象,可以向
公共表单LoadForm()
添加重载,以传递不同的
命名空间

using System.IO;
using System.Reflection;
using System.Windows.Forms;

internal class ResourceBag
{
    private string m_AssemblyName = string.Empty;
    private static Assembly asm = null;

    public ResourceBag() : this(null) { }

    public ResourceBag(string assemblyPath)
    {
        if (!string.IsNullOrEmpty(assemblyPath)) {
            this.AssemblyName = assemblyPath;
        }
    }

    public string NameSpace { get; set; }

    public string AssemblyName {
        get => m_AssemblyName;
        set {
            if (File.Exists(value)) {
                m_AssemblyName = value;
                asm = Assembly.LoadFrom(m_AssemblyName);
                this.NameSpace= asm.GetName().Name;
            }
            else {
                throw new ArgumentException("Invalid Assembly path");
            }
        }
    }

    public Form LoadForm(string formName, params object[] args)
    {
        if (asm == null) throw new BadImageFormatException("Resource Library not loaded");
        return Activator.CreateInstance(asm.GetType($"{NameSpace}.{formName}"), args) as Form;
    }
}

在此上下文中定义“但它不起作用”。@Flydog57我尝试过它object objForm=null;System.Reflection.Assembly Assembly=AppDomain.CurrentDomain.Load(File.ReadAllBytes(@“D:\Projetos C#\xmlvalidater\xmlvalidater\CompareXMLTools.exe”);objForm=assembly.CreateInstance(“CompareXMLTools.Main”,true,System.Reflection.bindingsflags.Default,null,新对象[]{},null,null);返回错误(System.MissingMethodException:'CompareXMLTools.Main类型中的构造函数'not found'。)项目B在启动时等待参数。命名空间CompareXMLTools{public partial class Main:Form{…….Main是一个方法而不是类型吗?我很好奇为什么你不只是使用
Assembly.Load
。你应该把这段代码放在你的问题中(你可以编辑它)@Marcos请将您在这些评论中发布的信息编辑到您的问题中。@Ian Kemp我更改了它,现在更好了?在此上下文中定义“但它不起作用”。@Flydog57我尝试过它object objForm=null;System.Reflection.Assembly=AppDomain.CurrentDomain.Load(File.ReadAllBytes(@“D:\Projetos C#\xmlvalidater\xmlvalidater\CompareXMLTools.exe”);objForm=assembly.CreateInstance(“CompareXMLTools.Main”,true,System.Reflection.bindingsflags.Default,null,new object[]{},null,null);返回错误(System.MissingMethodException:“CompareXMLTools.Main”类型中的构造函数未找到)项目B在启动时等待参数。命名空间CompareXMLTools{public partial class Main:Form{……..是Main是方法而不是类型吗?我很好奇