【发布时间】:2014-07-21 13:48:14
【问题描述】:
在 C# 中,混合泛型、接口和影子方法(C# 中的 new 关键字)似乎并不像预期的那样工作(在我看来)。 标记为新(阴影)的显式方法表现为覆盖方法!
这是一个用例:
创建一个C# winforms项目,去掉生成的Form1.cs 并用此代码替换 Program.cs:
using System;
using System.Text;
using System.Windows.Forms;
namespace GenericWithShadowedMethImplInterface
{
static class Program
{
[STAThread]
static void Main()
{
Application.Run(new ChildForm());
}
}
public interface IStepByStep_UI_Initialization
{
void FillControls();
void DefineBindings();
// etc...
}
public class BaseForm : Form, IStepByStep_UI_Initialization
{
public StringBuilder Log = new StringBuilder();
public BaseForm()
{
this.InstallSmartLoading();
Shown += (sender, args) => MessageBox.Show(Log.ToString());
}
public void FillControls()
{
Log.AppendLine("BaseObject.FillControls");
}
public void DefineBindings()
{
Log.AppendLine("BaseObject.DefineBinding");
}
}
public class ChildForm : BaseForm, IStepByStep_UI_Initialization
{
public ChildForm()
{
this.InstallSmartLoading();
}
// Shadowing is really what i want
public new void FillControls()
{
Log.AppendLine("ChildObject.FillControls");
}
// Shadowing is really what i want
public new void DefineBindings()
{
Log.AppendLine("ChildObject.DefineBinding");
}
}
public static class StepByStepInitializer
{
public static void InstallSmartLoading<TForm>(this TForm form)
where TForm : Form, IStepByStep_UI_Initialization
{
// i Use lambda to keep knowing what form type really is (BaseForm or ChildForm)
form.Load += (_, __) =>
{
// I would expect the these two lines of code here...
// Why these calls are treated as polymorphic calls ?
form.FillControls(); // always call ChildForm.FillControls even if typeof(TForm) == typeof(BaseForm)
form.DefineBindings();
// ... behaves likes this (not generic) code :
//if (typeof(TForm) == typeof(BaseForm))
//{
// (form as BaseForm).FillControls();
// (form as BaseForm).DefineBindings();
//}
//else if (typeof(TForm) == typeof(ChildForm))
//{
// (form as ChildForm).FillControls();
// (form as ChildForm).DefineBindings();
//}
};
}
}
}
运行它...
你应该看到:
ChildObject.FillControls ChildObject.DefineBindings ChildObject.FillControls ChildObject.DefineBindings现在,如果您在 InstallSmartLoading 中注释两行代码并取消注释其他代码行,然后再次运行该项目,您应该会看到:
BaseObject.FillControls BaseObject.DefineBindings ChildObject.FillControls ChildObject.DefineBindings所以我的问题很简单:为什么您注释的两行代码的行为与您未注释的代码不同?在初始化 ChildForm 之前,我需要完全初始化我的 baseBaseForm。这是泛型的限制吗? :((( 有解决办法吗
- TForm 表示真正的 Form 类型...
- 方法未标记为虚拟/覆盖,我明确使用 new 关键字
- 编译器不应该显示警告?
提前谢谢...
【问题讨论】:
-
您是否有 C++ 背景?在 C++ 中,当基类构造函数运行时,对象的“类型”就是该基类类型。而在 C# 中,对象在构造/销毁期间不会更改其类型 - 它们始终是最终类型。
-
“我需要在初始化 ChildForm 之前完全初始化我的基本 BaseForm。这是泛型的限制吗?:(((有解决方法吗?”只需在
ChildForm.FillControls()中调用base.FillControls();? -
@Damien_The_Unbeliever 是的,我的思想是建立在 C++ 之上的。尽管如此,我使用 C# 已有 6-7 年了,我确实喜欢它。这是我第一次发现代码不是很直观。
-
@Greg 因为在我们的项目中,我们想要定义一种标准的方式来初始化表单。目前我们有 7-8 个步骤:DefineBindings、FillControls、CustomizeUI、WireEvents 等……所以当我(或任何开发人员)想要做一个新表单时,规则很简单:实现这个接口并在 Constructor 中调用 Install。例如,初始化程序处理 Visual Studio 在表单加载事件中吞下异常的事实......此外,如果其他人想要调试或改进表单,即使他从未开发过此表单,他现在也将在哪里查看。
-
因此,当我(或任何开发人员)想要创建一个新表单时,规则很简单:实现此接口并在构造函数中调用 Install。 您发布的用于解决此问题的实现问题似乎令人难以置信的复杂,也许我错过了一些东西。如果这就是它的全部目的,我建议您将 BaseForm 抽象化(这不是绝对必要的)并按顺序在 BaseForm 上的某些私有方法中调用适当的方法。您可以以 WPF 窗口生命周期为例 codeproject.com/Articles/403418/…
标签: c# generics interface shadow