为什么泛型+接口+影子方法不能一起工作
本文关键字:不能 一起 子方法 工作 影子 泛型 接口 为什么 | 更新日期: 2023-09-27 18:13:58
在c#中,混合使用泛型、接口和影子方法(c#中的新关键字)似乎不会像预期的那样工作(在我看来)。标记为new (shadow)的显式方法表现为重写方法!
下面是一个用例:
创建一个c# winforms项目,删除生成的form .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。FillControlsChildObject。DefineBindingsChildObject。FillControlsChildObject。DefineBindings之前现在,如果你注释了InstallSmartLoading中的两行代码,并取消注释其他行代码,然后再次运行项目,你应该看到:
<>之前BaseObject。FillControlsBaseObject。DefineBindingsChildObject。FillControlsChildObject。DefineBindings之前所以我的问题很简单:为什么你注释的两行代码的行为不像你没有注释的代码?我需要我的BaseForm在初始化ChildForm之前被完全初始化。这是泛型的限制吗?:(((是否有解决方法
- TForm是指真正的Form类型。
- 方法没有标记为virtual/override,我显式地使用new关键字
- 编译器不应该显示关于这个的警告吗?
您有约束
where TForm : IStepByStep_UI_Initialization
(约束的另一部分现在不相关),然后你有一个变量(实际上是参数)
TForm form
你做什么:
form.FillControls(); // always call ChildForm.FillControls even if typeof(TForm) == typeof(BaseForm)
(你对问题的评论)。
它编译的原因是因为你有这个接口约束。
注意ChildForm
重新实现了BaseForm
已经实现的接口IStepByStep_UI_Initialization
所以你的调用实际上相当于
((IStepByStep_UI_Initialization)form).FillControls();
和与TForm
是什么无关。重要的是实例如何实现接口。
尝试以下操作:
- 停止重新实现接口,所以只在
BaseForm
, 或 实现它 - 将接口约束改为基类约束
where TForm : BaseForm
来加强你的理解。
下面是一个相关的例子,没有泛型,没有委托和事件,没有Win窗体:
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
是不相关的,这意味着它不会改变调用的方法。