IbrarMumtaz
IbrarMumtaz

Reputation: 4413

Cannot implement a multiple generic parameter based method with constraints?

I have the following Interface Declaration:

public interface IBasePresenter
{
    void Run();
    void ShowDialog<T, M>(T t, M m ) where T : UserControl where M : Form,      ISomeInterface<SomeType>;
}

The ShowDialog() is basically a method that will show a modal dialog box to the user. Where 'T' is the parent Form and M is the unique dialog to show. M of which there are multiple different types! Hence the reason to choose a generic method!

A couple of ways I think this method could be used:

Presenter.ShowDialog(this, typeof(Form1)); // FigA

Or

Presenter.ShowDialog(this, new Form1()); // FigB

Based upon Fig A or B, what exactly will a sample ShowDialog() method implementation look like?

My questions stems from trying to figure how the generic parameter 'M' is instantiated inside of a ShowDialog() method implementation.

Upvotes: 3

Views: 345

Answers (4)

IbrarMumtaz
IbrarMumtaz

Reputation: 4413

Below is an slightly updated version of the interface method:

    void ShowDialog<TParentForm, TDialogForm, TModel, TEntity>(TParentForm t, TDialogForm m, Action callback)
        where TParentForm : UserControl
        where TModel : class, IModel<TEntity>, new()
        where TDialogForm : Form, IEditableItem<TEntity>, new();

I made some assumptions on the previous version so during my testing and refinement phase the method signature has changed. It's still more or a less a en educational exercise for me so I still wanted to know how to pull it off rather than simple chose the easy way out.

A sample implementation of the method:

    public void ShowDialog<TParentForm, TDialogForm, TModel, TEntity>(TParentForm t, TDialogForm m, Action callback)
        where TParentForm : UserControl
        where TModel : class, IModel<TEntity>, new()
        where TDialogForm : Form, IEditableItem<TEntity>, new()
    {
        using (var dialogToShow = new TDialogForm())
        {
            dialogToShow.StartPosition = FormStartPosition.CenterScreen;
            dialogToShow.FormBorderStyle = FormBorderStyle.FixedSingle;
            dialogToShow.Model = new TModel();

            // 2. show the new user control/form to the user.
            var result = dialogToShow.ShowDialog(t);

            // 3. handle the dialog result returned and update the UI appropriately.
            if (result == DialogResult.OK)
            {
                // print status label.
                callback.Invoke();
            }
        }
    }

I am not entirely sure why the 'TDialogForm m' parameter is still in there as it does not seem to be used anywhere.

How to use the method:

    private void BtnAddNewServiceClick(object sender, EventArgs e)
    {            
        Presenter.ShowDialog<ServerRolesControl, AddNewServiceForm, ServiceModel, Role>(this, new AddNewServiceForm(), SetAddedRolesLabel);
    }

    private void BtnViewAllServicesClick(object sender, EventArgs e)
    {
        Presenter.ShowDialog<ServerRolesControl, ViewRolesForm, ServiceModel, Role>(this, new ViewRolesForm(), SetDeletedRolesLabel);
    }

I should update the interface method but it was so much pain getting it to work I would rather leave it alone now =).

Upvotes: 0

Spontifixus
Spontifixus

Reputation: 6660

You could change the generic method signature as follows:

public void ShowDialog<T>() where T : Form, new() {
    using(var dialog = new T()){
        dialog.ShowDialog();
    }
}

and then the call:

ShowDialog<MyCoolDialog>();

would result in the mtheod creating (not inferring this time ;)) a new instance of the form and showing it in a modal way.

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727067

You cannot use the Fig A way because typeof(Form1) is a System.Type, not a Form; the code will not compile unless there is an overload that takes a second parameter of type System.Type.

how the generic parameter 'M' is instantiated inside of a ShowDialog() method implementation?

It is not "instantiated" it is "inferred:. You provided the instance already; the compiler infers the type from the invocation.

Upvotes: 4

Marc Gravell
Marc Gravell

Reputation: 1064184

At a guess:

m.Controls.Add(t);
m.ShowDialog();

However, frankly I'm not sure this utility method adds much useful, and it could just as well be non-generic (void ShowDialog(Control t, Form m)). It could perhaps be more useful if using the : new() constraint, which would also avoid the risk of using the same control instance on multiple forms (illegal). But as I say: frankly I wouldn't bother with this method until it had demonstrated some non-trivial usefulness. And if I did keep it, I'd rename the parameters to be more illuminating; none of M, m, T, t tell me what they mean.

Upvotes: 5

Related Questions