在C#中,混合泛型,接口和阴影方法(C#中的新关键字)似乎没有像预期的那样起作用(在我看来)。 标记为新(阴影)的显式方法表现为重写方法!
以下是一个用例:
创建一个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之前完全初始化我的基本BaseForm。这是泛型的限制吗? :((( 有解决方法
提前致谢...
答案 0 :(得分:1)
你有约束
where TForm : IStepByStep_UI_Initialization
(约束的另一部分现在不相关),那么你有一个变量(实际参数)
TForm form
你做的事情:
form.FillControls(); // always call ChildForm.FillControls even if typeof(TForm) == typeof(BaseForm)
(你提出的问题)。
编译的原因是因为你有这个接口约束。
请注意ChildForm
重新实施 已IStepByStep_UI_Initialization
已实施的界面BaseForm
。
所以你的电话真的等同于
((IStepByStep_UI_Initialization)form).FillControls();
和与TForm
是无关。重要的是实例如何实现接口。
尝试以下方法:
BaseForm
,或 where TForm : BaseForm
以加强您的理解。
这是一个相关的例子,没有泛型,没有委托和事件,没有Win Forms:
interface ICanTalk
{
void Talk();
}
class Animal : ICanTalk
{
public void Talk()
{
Console.WriteLine("I am animal");
}
}
class Dog : Animal, ICanTalk // note: re-implements
{
public new void Talk() // note: method hiding "new" is always evil
{
Console.WriteLine("Wroof!");
}
}
static class Test
{
internal static void Run()
{
object x = new Dog();
((Animal)x).Talk(); // I am animal
((Dog)x).Talk(); // Wroof!
((ICanTalk)x).Talk(); // Wroof!
}
}
请注意,将object x = ...
上方更改为Animal x
或Dog x
是不相关的,这意味着它不会更改所谓的方法。