将通用摘要 class<T> 作为参数传递

Passing a generic abstract class<T> as an argument

我有一个 classes 的等级制度:

public abstract class AModel<T,U> where T : class where U : class
{
    protected IList<U> _children;
    protected readonly T _parent;
    protected readonly String _name;
    protected readonly String _urlStr;
    protected String _title;

    protected AModel(T parent, String name, String urlStr)
    {
        _parent = parent;
        _name = name;
        _urlStr = urlStr;
    }
    ...
}

我将它用于 5 个 class,每个都有 1 个 parent 和几个 children 例如:

public class Domain : AModel<Appellation, Bottle>
{        
    public Domain(Appellation pAppellation, string name, string urlStr) : base (pAppellation, name, urlStr)
    {
        _title = "Domaine : " + _name;
    }
    ...
}

这对于处理树视图非常有用

foreach (Domain domain in appellation.Children)
{
    _domains.Add(domain);
    domain.SetChildren(ReferentialDbManager.Instance.SelectBottles(domain));
    ...
}

现在我的问题是我想在以下情况下将 AModel 从我的树视图传递给 UserControl 构造函数:

private void OnSelectedNodeChange(object sender, TreeViewEventArgs e)
{
    _selectionGroupBox.Controls.Clear();
    switch (e.Node.Tag.ToString())
    {
        case "DOMAIN":
            AModel<Appellation, Bottle> selectedDomain = ReferentialManager.Instance.FindDomain(e.Node.Text);
            _selectionGroupBox.Controls.Add(new APanel(selectedDomain) { Dock = DockStyle.Fill });
            break;
        ...
    }
    ...
}

在 APanel 中,我将使用基础 AModel class 中的字段,因此我需要像这样传递它

public APanel(AModel<T, U> aObject)
{
    InitializeComponent();
    _titleLabel.SetTitleString(aObject.Title);
}

如何将通用 AModel class 作为参数传递?

谢谢

您需要为类型参数提供值:

public APanel(AModel<Appellation, Bottle> aObject) { }

或者您还需要使 APanel 通用:

public class APanel<T,U> where T : class where U : class
{    
    public APanel(AModel<T, U> aObject) { }
}

如果面板不需要 AModel 的 "generic" 部分,我建议你为 AModel 创建一个非通用的 base-class 或接口,并在将其提供给 APanel 之前将其转换为:

public abstract class AModelBase {
    // non-generic stuff
    protected readonly String _name;
    protected readonly String _urlStr;
    protected String _title;
}

public abstract class AModel<T,U> : AModelBase where T : class where U : class
{
    // generic stuff
    protected IList<U> _children;
    protected readonly T _parent;    
}

public APanel(AModelBase model)
{
    InitializeComponent();
    _titleLabel.SetTitleString(model.Title);
}

泛型编程用于描述类型之间可互换的行为。

要在 APanel 控件中使用此通用行为,编译器需要知道用于构造 APanel.

的类型

如果您打算将多个类型与 APanel 控件一起使用,请将 APanel 描述为通用类型。

对于 WinForms 控件,您需要更改 APanel.csAPanel.Designer.cs 文件。

APanel.cs:

public partial class APanel<TParent, TChild> : UserControl
    where TParent: class
    where TChild: class

{
    public APanel(AModel<TParent, TChild> model)
    {
        InitializeComponent();
        _titleLabel.SetTitleString(model.Title);
    }
}

APanel.Designer.cs:

partial class APanel<TParent, TChild>
{
    // Change the type declaration
    // leave the inside of the class alone
}

否则您需要向构造函数提供完整的具体类型。

public class APanel : UserControl
{
    public APanel(AModel<Appellation, Bottle> model)
    {
        InitializeComponent();
        _titleLabel.SetTitleString(model.Title);
    }
}