铸造用户控制
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;
...
在 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;
...