我想知道以下是否可行:
class A
{
public int SomeMethod()
{
return 1;
}
}
class B : A
{
public override int SomeMethod()
{
return 3;
}
}
class DrivingClass
{
public static void Main()
{
B classB = new B();
A classA = (A)classB;
Assert.IsEqual(3, classA.SomeMethod());
}
}
这个失败当然是期望3但是实际是1.是否有一种方法(没有将其类型转回B),因为classA.SomeMethod()调用被覆盖的版本,因为它最初是B(尽管我认为这个知识是失败一次铸造)。
更新: 已经编写了A类,并且无法编辑所有意图和目的。我只能控制B类。知道B类将被输入A类,我只想在我的类型化的B上调用SomeMethod()时使用我的实现。
答案 0 :(得分:3)
SomeMethod
需要在A中声明为虚拟才能在B中成功覆盖。
public virtual int SomeMethod() // in A
public override int SomeMethod() // in B
正确到位
A a = new B();
int value = a.SomeMethod();
Debug.Assert(value == 3); // succeeds
如果你而有
public int SomeMethod() // in A
public new int SomeMethod() // in B, or just
public int SomeMethod() // in B
然后上面的断言失败了。 B中的方法隐藏了基本方法,但只能通过B引用。在A的引用下操作时,您将获得基本行为。
A a = new B();
int value = a.SomeMethod(); // gets 1 from A, not 3 from B
更新:已经编写了A类,并且无法编辑所有意图和目的。我只能控制B类。知道B类将被输入A类,我只想在我的类型化的B上调用SomeMethod()时使用我的实现。
默认情况下,C#中的方法不是虚拟的。如果A
的作者没有考虑到可扩展性(至少,至于覆盖SomeMethod
),那么当B
时,您将无法替换或覆盖该行为。它被视为A
。但是,如果你能够控制强制转换,或者更确切地说是代码的依赖关系,你可以将其反转,以便A
实际上遵守B
的合同,而不是相反。例如,考虑适配器模式。
interface IB
{
int SomeMethod();
}
class B : IB
{
public int SomeMethod() { return 3; }
}
class ABAdapter : IB
{
private A a;
public ABAdapter(A a) { this.a = a; }
public int SomeMethod() { return a.SomeMethod(); }
}
在此示例中,您已使用适配器进行模式化,以使A
通过B
接口实际履行IB
的约定。因此,曾经依赖A
或B
的代码现在可以依赖IB
。 ABAdapter只是委托给A实现。
public void DoSomething(IB ib) // given
A a = new A();
DoSomething(new ABAdapter(a)); // invoke with A
DoSomething(new B()); // invoke with B
答案 1 :(得分:1)
您尚未在SomeMethod
中声明A
是虚拟的,所以这显然不是您的真实代码(否则B
无法覆盖它)但是当您制作时如果发生变化,将返回3.如果没有,多态将完全被破坏。
现在,我们对您发布的代码所做的另一项更改是在B.如果您使用:
public new int SomeMethod()
{
return 3;
}
然后你的断言会失败 - 因为它会A.SomeMethod()
通过{{1}调用阴影或隐藏 },没有被覆盖。基本上,如果你想要多态行为,你需要使用B.SomeMethod()
,它必须是虚拟方法。
答案 2 :(得分:0)
我建议您阅读here主题 在文章中,它显示了这些代码示例:
class A
{
public void F() { Console.WriteLine("A.F"); }
public virtual void G() { Console.WriteLine("A.G"); }
}
class B: A
{
new public void F() { Console.WriteLine("B.F"); }
public override void G() { Console.WriteLine("B.G"); }
}
class Test
{
static void Main() {
B b = new B();
A a = b;
a.F(); //prints A.F
b.F(); //prints B.F
a.G(); //prints B.G (due to virtual method override)
b.G(); //prints B.G
}
}
答案 3 :(得分:0)
鉴于您的编辑声明您无法重新定义课程A
,我担心您或多或少会失去运气。
可以从B
派生A
,然后声明new int SomeMethod()
,但您无法使用A
引用调用该方法。您可以使用运行时类型检查:
int CallSomeMethod(A obj)
{
var b = obj as B;
return b == null ? obj.SomeMethod() : b.SomeMethod();
}