C# 声明由子类实现的方法的正确方法是什么?

C# 声明由子类实现的方法的正确方法是什么?,c#,inheritance,implementation,icommand,C#,Inheritance,Implementation,Icommand,我创建了一个具有公共方法的父类,但也有一些方法希望由子类实现。i、 e.点击执行方法 实施这一点的正确方式是什么 public Parent { CancelCommand = new RelayCommand(CancelClicked, CancelCanExecute); private void CancelClick(object param) { // Do stuff } } public Child : Parent { priv

我创建了一个具有公共方法的父类,但也有一些方法希望由子类实现。i、 e.点击执行方法

实施这一点的正确方式是什么

public Parent {
    CancelCommand = new RelayCommand(CancelClicked, CancelCanExecute);
    private void CancelClick(object param) {
        // Do stuff
    }
}

public Child : Parent {
    private bool CancelCanExecute(object param) {
        // Do stuff
        return true;
    }
}
其中CancelClick由父类托管,CancelCanExecute由子类处理


我会用外人吗?还是应该使用接口?如果我在子类中使用override,它不会强迫我实现该方法。我不确定是否应该将父类更改为抽象类,因为它具有非抽象方法等。

因此,以下是您的选项:

1.将您的基类声明为
抽象类以及一些方法

这种方法有两个优点:您可以自由地在基类上实现公共方法(也就是说,并非所有方法都需要是
抽象的
),而任何抽象方法都必须在派生类上重写。有一个计数器点(您可能知道):您不能实例化它。也就是说,你不能这样做:

Base obj = new Base();
但是,您仍然能够做到这一点:

Base obj = new Child();
2.使用接口

您可以声明一些接口来强制类实现一些方法。然而,继承和接口之间的语义是完全不同的。你必须决定哪个最适合你的工作


嗯,您可以选择第一个选项。

您需要在父级中指定一个抽象方法:

public abstract class Parent
{
    public void DoSomething()
    {
        // Do something here...
    }

    public abstract void ForceChildToDoSomething();
}
这会迫使孩子实现它:

public class Child : Parent
{
    public override void ForceChildToDoSomething()
    {
        // Do something...
    }
}
但是,现在您将有一个抽象的父对象。因此,如果您想使用Parent中的功能,您需要执行以下操作:

Parent parent = new Child();
parent.DoSomething();
parent.ForceChildToDoSomething();
是的,摘要:

public abstract Parent
{
  protected abstract bool CancelCanExecute(object param);
  //more stuff
}
它也可以是
公共的
,但不能是
私有的


现在你不能有一个派生类既不能实现
CancelCanExecute
,也不能自己是
abstract
,所以要强制进一步的派生类来实现它。

你应该定义一个接口,然后你的代码应该只接受实现该接口的对象。虽然使用
abstract
并创建公共基类非常诱人,但这种方法(几乎)从定义上来说是错误的(几乎)

在C#和其他不允许多重继承的语言中,创建一个基类只是为了定义一个其他人必须填充的空“骨架”,并强制每个人使用它是非常有限的。每个人都必须从中继承,因此,例如,他们将无法重用自己现有的类层次结构,或者必须创建繁琐的桥或(…)

如果抽象基类只有一个/几个/十几个/一百个抽象方法、事件和属性,那么它应该是一个接口,因为它只定义了“公共需求”

使用公共内容创建新抽象库的唯一合理理由是实际提供默认实现。不过,对于这样的基类,也应该定义一个接口,基类应该实现它,并允许重写,甚至可能将某些内容标记为实际抽象的内容——但您的代码仍然应该通过接口引用所有内容,而不是基类。这样的抽象基础应该是实现者的帮助/快捷方式,而不是强制性的。如果有人想从头开始做任何事情,他将实现接口,并用示例代码忽略基础,而您的代码仍然可以很好地使用它。尽管如此,所有公共代码都可以作为一组在该接口上操作的静态帮助器类提供

抽象基类实际上是需要的,在某些情况下不能用接口代替,例如,当您必须强制派生类具有参数构造函数时,或者您自己必须从某个对象派生时,例如,像WPF Visual、UIElement或DependencyObject一样,微软的设计在这里也有一些缺陷。他们强制从基类派生,这会在许多地方影响到开发人员(例如,EntityFramework中的数据模型对象不是依赖对象等)。尽管如此,我认为他们应该从中抽象出来——从视觉和朋友的角度来看,没有那么多的内部例程无法提升到接口。。我不认为他们这样做仅仅是因为,相反,我认为这是关于性能和减少类型转换/方法调度

请注意,我所说的一切并不完全符合你在问题中提出的内容。在这里,您已经假设“父/基类将处理XYZ”。这意味着,您在一开始就放弃了接口方法。使用接口,您将只定义click和cancelclick必须存在,但您将无法实施/提供“基本实现”。这样的事情你可以做的基础课。因此,我认为您应该采用开放/混合的方法:定义接口,定义静态可重用处理程序,只使用接口,并为一些“懒惰的程序员”提供基类:

这可能看起来非常臃肿,但它是非常开放的定制。尽管有了开放性,几乎没有办法强制每个人都必须使用“ClickableImpl”。有一些方法,但是。。它们将包括更多的膨胀和时间/内存开销,我认为它们现在不值得描述


请记住,要估计谁、如何以及有多少人将在将来使用此代码。如果是一个/两个/五个用途,请坚持使用抽象基础。但是,如果您感觉到有几十个或数百个子实现,那么最好添加一个小膨胀,这样以后可能会节省很多时间。

您可以将基本方法设置为
abstract
,但是您不会强制子类实现它。为此,仅当子类为
abstrac时,才应编写
接口
@AndreCalil
public interface IClickable
{
    ICommand CancelCommand { get; }
    void CancelClick();
    bool CanCancelClick();
}

public static class ClickableDefaultImpl
{
    public static void DefaultCancelClick(IClickable obj)
    {
        ... do the common things on the OBJ
    }
    public static bool DefaultCanCancelClick(IClickable obj)
    {
        ... do the common things on the OBJ
    }
}

public abstract class Clickable : IClickable
{
    public void CancelClick() { ClickableDefaultImpl.CancelClick(this); }
    public bool CanCancelClick() { return ClickableDefaultImpl.CanCancelClick(this);  }
}