如何使用此通用方法将参数传递给表单?

How can I pass Parameters to the Form with this Generic Method?

我有这个在面板中打开表单的通用方法,这个方法继承自 Form,目前的限制是它有一个空构造函数 (where T : Form, new())

public void OpenForms<T>() where T : Form, new()
{
    Form form = container_panel.Controls.OfType<T>().FirstOrDefault();
    if (form !=null)
    {
        //If the instance is minimized we leave it in its normal state
        if (form.WindowState == FormWindowState.Minimized)
        {
            form.WindowState = FormWindowState.Normal;
        }
        //If the instance exists, I put it in the foreground
        form.BringToFront();
        return;
    }
    //The form opens
    form = new T();
    form.TopLevel = false;
    container_panel.Controls.Add(form);
    container_panel.Tag = form;
    form.Show();
}

这样调用:

OpenForms<Form1>();

如何调整此函数以将参数传递给表单?

在这种情况下,我需要向表单传递两个参数,如下所示:

OpenForms<Form1>(param1, param2);

Not all forms receive parameters, but in the future, you may need to use 1/2/3 parameters depending on the form.

The parameters can vary in type, either: bool, string, int ...

这个可以收到这样的东西:

public void OpenForms<T>(params object[] args) where T : Form, new() { ... }

想法是能够通过以下方式使用它:

object[] args = new object[] { "a", true };

OpenForms<Form1>(args);
OpenForms<Form1>("a", 2, false);
OpenForms<Form1>();

当您收到参数后,您可以在创建表单时使用它们。

知道如何实现吗?

编辑:

我想这两个表格的例子

public partial class Form1 : Form
{
    public Form1(string param1, bool param2)
    {
        InitializeComponent();
    }

    //......
}

public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();
    }

    //......
}

尝试拨打这样的电话时:

OpenForms<Form1>("a" false); //Error
OpenForms<Form2>();

错误:

must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'AbrirFormulario(params object[])'

为此,您需要删除 new() 约束以允许没有无参数构造函数的表单:

public void OpenForms<T>(params object[] args) where T : Form

现在,为了创建实例,您需要使用 Activator.CreateInstance:

T form = default(T);

if (args == null || args.Length == 0)
    form = Activator.CreateInstance<T>();
else
    form = (T)Activator.CreateInstance(typeof(T), args);

编辑:完整解决方案

public void OpenForms<T>(params object[] args) where T : Form
{
    Form form = container_panel.Controls.OfType<T>().FirstOrDefault();
    if (form !=null)
    {
        //If the instance is minimized we leave it in its normal state
        if (form.WindowState == FormWindowState.Minimized)
        {
            form.WindowState = FormWindowState.Normal;
        }
        //If the instance exists, I put it in the foreground
        form.BringToFront();
        return;
    }
    if (args == null || args.Length == 0)
        form = Activator.CreateInstance<T>();
    else
        form = (T)Activator.CreateInstance(typeof(T), args);
    form.TopLevel = false;
    container_panel.Controls.Add(form);
    container_panel.Tag = form;
    form.Show();
}

另一种解决方案是创建一个 Interface 来创建一个允许接收参数的方法。

这是一个例子:

public interface IForms
{
    void InitializeParameters(params object[] args);
}

这里我们定义了一个方法,InitializeParameters必须符合实现这个接口的形式。

后面在必须从泛型窗体中调用的窗体中,我们在其定义中添加接口,以及强制方法:

public partial class Form1 : Form, IForms
{
    public Form1()
    {
        InitializeComponent();
    }

    public void InitializeParameters(params object[] args)
    {
        if (args.Length==2)
        {
            string param1 = args[0].ToString();
            int param2 = (int)args[1];
        }
        else
        {
            throw new Exception("The number of parameters is incorrect");
        }

    }       
}

现在我们定义通用方法以如下方式打开表单:

private void OpenForms<T>(params object[] args) where T : Form,IForms,  new()
{
    Form form;
    form= new T();
    ((IForms)form).InitializeParameters(args);
    form.Show();
}

最后,使用方法如下:

OpenForms<Form1>("a", 2);
OpenForms<Form2>("a", 2, "b");
OpenForms<Form3>();

It must be taken into account that as the InitializeParameters method has been defined, examples 2 and 3 will give an exception for an incorrect number of parameters. With this form, each case must be controlled.

感谢用户@Pikoh的帮助。

这是另一种方法,它不需要 Form 来实现接口或真正关心它是如何构建的。

假设我们有一个 Form,仅用于测试目的:

public class Form3 : Form
{
    public Form3(bool someParameter, string someTitle)
    {

    }
}

现在有一些关于构造函数的有用的自文档特征,即参数有名称。使用这样的东西:

public void OpenForms<T>(params object[] args) where T : Form
{
    //...
}

不向调用者提供有关 "arguments" 是什么、它们属于什么顺序或它们的含义的任何信息。所以当你这样称呼它时:

OpenForms<Form3>(true, "Some Value");

Intellisense 对您没有帮助,因为它只是表明您需要向该方法传递一些(或不传递)参数。相反,更好的方法是使用工厂 Func<T> 来构建表单:

public void OpenForms<T>(Func<T> factoryMethod) where T : Form
{
    Form form = container_panel.Controls.OfType<T>().FirstOrDefault();
    if (form != null)
    {
        //If the instance is minimized we leave it in its normal state
        if (form.WindowState == FormWindowState.Minimized)
        {
            form.WindowState = FormWindowState.Normal;
        }
        //If the instance exists, I put it in the foreground
        form.BringToFront();
        return;
    }
    form = factoryMethod();
    form.TopLevel = false;
    container_panel.Controls.Add(form);
    container_panel.Tag = form;
    form.Show();
}

然后像这样调用(注意您还可以省略 OpenForms 调用的 <Form3> 部分,这是推断的!):

OpenForms(() => new Form3(true, "Title"));

伴随着所有有用的智能感知:

所以现在您有了自记录代码,表单的构造方式无关紧要,并且您不会强制使用没有关于哪些参数属于何处的真实文档(在代码中)的接口。