铸造用户控制

Casting User Control

在 winforms 中,我想将 UserControl 转换为特定的用户控件,这样我就可以访问其 public 成员。

我的设置是这样的:

enum ePage
{
    Setup,
    AddMorePagesHere
}

var _pages = new List<UserControl>();

protected override void OnLoad(EventArgs e)
{
    _pages.Add(new ucSetup());
    _pages.Add(new ucAddMorePagesHere());
    base.OnLoad(e);
}

现在和

有区别吗
(_pages[(int)ePage.Setup] as ucSetup).SetupMethod();

((ucSetup)_pages[(int)ePage.Setup]).SetupMethod();

你会怎么做?

“作为”演员表

(_pages[(int)ePage.Setup] as usSetup).SetupMethod();

如果_pages[(int)ePage.Setup]不是usSetup,你会在这里得到NullReferenceException,因为(_pages[(int)ePage.Setup] as usSetup)会return null。

直接投

((ucSetup)_pages[(int)ePage.Setup]).SetupMethod();

如果_pages[(int)ePage.Setup]不是usSetup,你会在这里得到InvalidCastException

除此之外,没有区别。

顺便说一下,我鼓励您遵循 .NET 命名准则。您的 类 应命名为 UCSetup(或 UcSetup)和 UCAddMorePagesHere(或 UcAddMorePagesHere)。

备选

如果您执行以下操作,您可以简化代码:

public abstract class SetupPage : UserControl
{
    public abstract void SetupMethod();
}  

public class UcSetup : SetupPage
{
    public override void SetupMethod()
    {
        // Do something here
    }
}

public class UcAddMorePagesHere : SetupPage
{
    public override void SetupMethod()
    {
         // Do something here
    }
}

然后,不再保留 UserControl 的列表,而是保留 SetupPage 的列表

var _pages = new List<SetupPage>();

您将能够在不强制转换的情况下调用您的方法:

_pages[(int)ePage.Setup].SetupMethod();

您显示的两行代码在功能上没有区别。

但是第一个给你更多的灵活性和能力来检查 _pages[(int)ePage.Setup] 是否是 usSetup 以防止 NullReferenceException.

像这样:

var x = _pages[(int)ePage.Setup] as usSetup;
if (x != null)
    x.SetupMethod();

在你的第二种情况下,你不能做这样的检查,如果 _pages[(int)ePage.Setup] 的类型与 usSetup 不兼容,它将被抛出异常。

对您来说重要的区别在于:

(_pages[(int)ePage.Setup] as usSetup).SetupMethod();

可能会抛出 NullReferenceException 如果您正在投射的控件不是 usSetup,因为 as 运算符然后 returns null.

((ucSetup)_pages[(int)ePage.Setup]).SetupMethod(); 

可能会抛出 InvalidCastException.

只要您确定要投射正确的对象,您就可以安全地使用其中任何一个。

实际上,我会确保每个 ePage 值真的只有一个控件,所以我会使用字典而不是列表:

Dictionary<ePage, UserControl> pages = new ...;
pages[ePage.Setup] = new usSetup();
pages[ePage.Other] = new ...;

var page = pages[ePage.Setup] as usSetup;
...