我的项目中需要多个Form类。所以我想把这些形式的所有共同点放在抽象课堂上。这个类将有一个固有的Form类和一个接口。类似于
public interface IMyForm
{
void Init();
}
public abstract class AMyForm : Form, IMyForm
{
void IBrowser.Init()
{
throw new NotImplementedException();
}
}
public partial class MainClass : AMyForm
{
// But here the warning is shown (That i have to add override keyword),
// but when i do, The error is shown that i cannot override from non abstract thing
public void Init()
{
}
}
你能告诉我如何做到这一点吗?
虽然Jon Skeets的答案对于一般编程来说是正确的,但我建议不要在窗体和用户控件上使用抽象类。第一个问题是,设计器将无法创建抽象类的实例,因此将无法在设计器中显示继承FROM抽象窗体的窗体。这意味着您将无法通过设计器向窗体添加新控件,除非(如下面的注释中所建议的)添加一个实现抽象类的代理类,然后用作其他继承窗体的基,例如:AbstractMyForm -> MyFormSurrogate -> MyForm
。
第二个更大的问题是,在我看来,这意味着你试图把逻辑融入形式。这是通常不需要的,尤其是当您最终将业务逻辑与显示技术耦合时,在本例中为Winforms
。我的建议是,尝试使用模型视图演示器模式在普通类中尽可能多地分离逻辑(使用抽象类、接口等),然后将它们数据绑定到表单。如果存在共享的视觉部分(例如:一组复选框),请为这些部分制作用户控件,然后在表单上重用它们。
我希望我没有过多地假设你对使用winforms的了解,但当我开始从事GUI开发时,我也有类似的问题。
您只想而不是在抽象类中使用显式接口实现
public abstract class AMyForm : Form, IMyForm
{
public virtual void Init()
{
throw new NotImplementedException();
}
}
或者只是把它抽象化:
public abstract class AMyForm : Form, IMyForm
{
public abstract void Init();
}
在这两种情况下,您只需在具体类中重写它。
或者,如果真的想在抽象类中使用显式接口实现,那么应该在具体类中再次使用它:
public partial class MainClass : AMyForm, IMyForm
{
void IMyForm.Init()
{
// Stuff
}
}
缺点是,没有这样做的AMyForm
的任何子类基本上都会有坏的IMyForm
实现。使用第一种方法更好。
编辑:或者,根据超级跑车的建议:
public abstract class AMyForm : Form, IMyForm
{
void IBrowser.Init()
{
InitImpl();
// And anything else you need...
}
// Or abstract...
protected virtual void InitImpl()
{
}
}
然后在具体类中重写InitImpl
。
设计视图中不显示抽象类;您可以通过向抽象类添加编译器if语句来绕过它,使其在设计时不抽象。
#if RELEASE
public abstract class AbstractForm : Form, IInterface
#else
public class AbstractForm : Form, IInterface
#endif
{
// Your abstract code here.
}
这是一个很好的小技巧,效果很好。您可以使用相同的技巧在设计时和运行时之间切换虚拟方法和抽象方法。
附录:
应该注意的是,使用抽象形式是不必要的。从非抽象表单继承它更高效,并且产生的潜在问题更少
public partial class Screen : Form, IInterface
{
// Base Class here, complete with .designer.cs and .resx
public Screen()
{
InitialiseComponent();
}
#region IInterface imported methods
public partial void SomeMethod()
{
// Do something.
}
#endregion
}
然后,如果你想创建一个登录屏幕,例如:
public partial class LogonScreen : Screen, IInterface
{
// Derived Class here, complete with .designer.cs and .resx
public Screen()
{
InitialiseComponent();
}
#region IInterface imported methods
public partial void SomeMethod()
{
// Do more somethings!
}
#endregion
}