我想在C#中覆盖一个方法,但我有一个不同的签名
基类用户应该访问原始方法
class A public init()
派生类用户应仅使用派生方法。
class B public init(int info)
我不能使用“覆盖”bc有一个不同的签名。 我有什么选项,以便派生类用户看不到两个方法。
笔记。 总而言之,我只需要两个共享一些代码的类。 inheritance不是必须的。 但B的用户的简单性是优先考虑的事项。
这是一个很大的代码气味(违反了一些基本的OOP原则),据我所知,不能用任何语言来完成。 在OOP中, B
的实例是A
的实例; 这是多态性 。 因此,如果A
有一个名为init
的公共方法,不接受任何参数,那么B
也是如此。
你想要做什么呢?
编辑:既然您已经添加了表明inheritance不是必须的编辑,只需使用组合来共享代码。 例如,为B
的私有实例。
根据Liskov原则,你根本不能这样做,因为它违反了这个原则。 您可以做的最好的事情是覆盖派生类中的init()
并使其在每次调用时抛出exception,声明用户应该使用init(int info)
并依靠测试来捕获错误。
为什么你不能简单地替换init()方法甚至使它受到保护?
Liskov原则陈述(改述)在需要class A
实例的情况下,可以传递class B extends A
。 如果方法需要A
并希望在其上调用init()
并使用protected init()
将B
传递给它( extends A
),则该方法将失败。 这就是代码甚至无法编译的原因。
由于类型系统的性质,你所要求的是不可能的。 B的任何实例都可以被认为是A,因此您可以调用任何A的方法(包括Init()
)。 您可以做的最好是在B中重载Init()
并抛出exception以在运行时捕获它。
public class B { void Init() { throw new NotSupportedException(); } }
与此处的一些答案/评论相反,如果存在,您所要求的内容将具有实际用途:
class Derived : Base {
通过考虑解决方法可以看出这一点:
class Derived { private Base _base = new Base();
换句话说,它根本不是一个基类,而是实现的隐藏部分。
这种解决方法的缺点是:什么Base有一个你必须提供的抽象方法? 你必须这样写:
class Derived { class ActualDerived : Base { // override abstract method(s) } private Base _base = new ActualDerived();
这是私有inheritance的全部要点(如C ++中所见) – 它适用于您希望inheritance实现但不是“接口”(非正式意义上)的情况。
但在C#中,它不可用。
据推测,A和B有一些共同之处。 你能把它分解成不同的基类吗?
public class Base { ... common stuff ... } public class A : Base { public void Init() { } } public class B : Base { public void Init(int info) { } }
如果你需要多态,那么引用Base,或者更好的是,Thomas的接口是要走的路。
而不是inheritance,使用接口作为“中间人”:
public interface IAllThatYouNeed { public void DoSomeStuff(); } public class A : IAllThatYouNeed { public void Init() { // do stuff } } public class B : IAllThatYouNeed { public void Init(int info) { // do stuff } }
它看起来还不可能
我试图做这样的事情:
public class B : A { private override void Init() { } public void Init(int x) { } }
但是Init()它仍然可以从A类中看到
这里没有完美的解决方案。 一些可行的方法:
一种方法是使A.Init()成为虚拟,在B中覆盖它并使其抛出NotImplementedException / InvalidOperationException。
Init()保持可见,但是用户很快发现它不被使用(明确表示要在XML文档和exception消息中使用Init(int info))。
如果您不关心inheritance部分并且只想在B类中使用A类的function,那么不要从A派生B并使B实例化A并使用其function。
编辑:您可以使用实现公共操作的接口来保留inheritance,同时避免在B中实现Init():
public interface IOperations { void DoStuff(); void Foo(); } public class A : IOperations { public void Init() { // Do class A init stuff } #region IOperations Members public void DoStuff() { // ... } public void Foo() { // ... } #endregion } public class B : IOperations { A _operations = new A(); public void Init(int initData) { _operations.Init(); // Do class B init stuff } #region IOperations Members public void DoStuff() { _operations.DoStuff(); } public void Foo() { _operations.Foo(); } #endregion }
使用工厂可以做得更好:
public static class OperationsFactory { public static IOperations CreateOperations() { A result = new A(); result.Init(); return result; } public static IOperations CreateOperations(int initData) { B result = new B(); result.Init(initData); return result; } }
这种方式实例化代码被很好地封装,两个Init()方法之间的差异从用户代码中隐藏。