C#子类型已强制转换为超类型,但仍希望调用该子类型方法
本文关键字:类型 希望 方法 调用 转换 超类 | 更新日期: 2023-09-27 18:19:38
我想知道以下是否可能:
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()时使用我的实现。
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
UPDATE:类A已经编写好了,对于所有的意图和目的都不能编辑。我只能控制类B。知道类B将被转换为类型A,我只想在对我的类型转换的B调用SomeMethod()时使用我的实现。
默认情况下,C#中的方法不是虚拟的。如果A
的作者在设计它时没有考虑到可扩展性(至少,就覆盖SomeMethod
而言),那么当它被视为A
时,您将无法用B
替换或覆盖该行为。但是,如果您可以控制强制转换,或者更确切地说是代码的依赖关系,您可以将其反转,以便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
通过IB
接口实际履行了B
的约定。因此,曾经可能依赖于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
您还没有在A
中声明SomeMethod
是虚拟的,所以这显然不是您的真实代码(否则B
无法覆盖它),但当您进行更改时,它将返回3。如果不这样做,多态性就会被彻底打破。
现在,我们可以对你发布的代码进行的另一个更改是在B中。如果你使用:
public new int SomeMethod()
{
return 3;
}
然后您的断言将失败,因为它将调用A.SomeMethod()
,而B.SomeMethod()
将遮蔽或隐藏。基本上,如果您想要多态行为,您需要使用override
,并且它必须在虚拟方法上。
我建议阅读此处的主题在文章中,它展示了以下代码示例:
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
}
}
鉴于您的编辑声明您无法重新定义类A
,恐怕您或多或少有些运气不好。
可以从A
派生B
,然后声明new int SomeMethod()
,但不能使用A
引用调用该方法。您可以使用运行时类型检查:
int CallSomeMethod(A obj)
{
var b = obj as B;
return b == null ? obj.SomeMethod() : b.SomeMethod();
}