【问题标题】:C# Form that inherit Abstract class AND implements interface.继承抽象类并实现接口的 C# 表单。
【发布时间】:2012-07-15 12:43:43
【问题描述】:

我的项目中需要有多个表单类。因此正在考虑将这些形式共有的所有内容放在抽象类中。该类将具有继承的 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() 
    {
    }
}

你能告诉我如何实现吗?

【问题讨论】:

    标签: c# winforms interface abstract-class


    【解决方案1】:

    您只想在抽象类中使用显式接口实现:

    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 实现。在这里使用第一种方法更好。

    编辑:或者,根据 supercat 的建议:

    public abstract class AMyForm : Form, IMyForm
    {
        void IBrowser.Init()
        {
            InitImpl();
            // And anything else you need...
        }     
    
        // Or abstract...
        protected virtual void InitImpl()
        {
        }
    }
    

    然后在你的具体类中覆盖InitImpl

    【讨论】:

    • 嗨,谢谢重播。那么,创建具有多个相似表单的应用程序(避免糟糕的编码实践)的最佳方法是什么?我想做接口(必要方法列表),抽象类(一些方法的默认行为)和ofc具体类,它继承了Form类......
    • @Marshall:我还没有完成足够的 GUI 开发来给出一个非常好的答案,但是我向您展示的任何一种方法应该工作......
    • 如果想要使用显式接口实现,正确的方法是不要让派生类重新派生接口,而是使用非虚拟显式实现,除了调用 protected virtual 之外什么都不做方法;然后派生类应该覆盖它。
    • @supercat:是的,这是另一种选择 - 将添加它。
    • @supercat 感谢您的重播。但我不确定我是否理解正确。你能给我写一个你想法的简短源代码吗?只是为了确保..谢谢
    【解决方案2】:

    虽然 Jon Skeets 的回答对于一般编程来说是正确的,但我建议 AGAINST 在表单和用户控件上使用抽象类。第一个问题是,该设计器将无法创建抽象类的实例,因此将无法在设计器中显示继承 FROM 抽象表单的表单。这意味着您将无法通过设计器向表单添加新控件,除非 - 如下面的 cmets 中所建议 - 您添加一个实现抽象类的代理类,然后用作其他类的基础继承形式,例如:AbstractMyForm -> MyFormSurrogate -> MyForm

    在我看来,第二个也是更大的问题是,这意味着您正试图将逻辑融入表单。这通常是不希望的,尤其是当您最终将业务逻辑与显示技术耦合时,在本例中为Winforms。我的建议是尝试使用Model View Presenter pattern 在普通类(使用抽象类、接口等)中分离尽可能多的逻辑,然后将data bind 分离到表单中。如果有共享的可视部分(例如:一组复选框),请为这些部分制作用户控件,然后在表单上重复使用它们。

    我希望我没有过多地假设您对使用 winforms 有太多了解,但是当我开始从事 GUI 开发时,我遇到了类似的问题。

    【讨论】:

    • 您可以使用一个代理非抽象类来简单地克服这一限制,然后将其用作表单的超类。 IE。 AbstractMyForm -> MyFormSurrogate -> MyForm。这种方法甚至允许在超类中使用泛型。
    • @Miroslav 谢谢!我根据您的评论更新了我的答案。我不确定我在撰写本文时是否意识到这一点,后来我忘记了。但我仍然建议不要使用这种方法,因为它通常会变得一团糟。
    • 有时,这只是必要的......例如我已经实现了自己的 MVP 基础架构,其中之一是 FormView(它是 Form,接受 Presenter 实例),它需要是通用的(因此它提供了有效类型的 Presenter 属性等)。如果你总是(按照惯例)在主类下面包含代理类,那一点也不乱。
    • 我并不是说如果你需要它,就不应该这样做。但是,在构建 UI 方面经验不足的人可能甚至不知道 MVP 和数据绑定,最终可能会构建复杂的层次结构,其中充满了表单中的代码隐藏。我知道我已经做到了,我宁愿早日找到更好的方向。
    【解决方案3】:

    抽象类不在设计视图中显示;您可以通过在抽象类中添加编译器 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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-03
      • 2013-01-09
      • 2018-04-05
      • 1970-01-01
      • 2012-04-11
      • 1970-01-01
      • 2013-10-17
      • 2011-09-16
      相关资源
      最近更新 更多