如何从超类调用两个子类的公共名称方法
本文关键字:子类 方法 两个 超类 调用 | 更新日期: 2023-09-27 18:20:11
在我的日常工作时间里,我遇到了一个问题:
假设:
- 我们有一个对象a,它是
Object
类型 -
A可能是类型
B
或类型C
- 类型
B
和C
具有相同的名称方法GetSomething()
- 类型
B
和C
继承自Object
,这没有任何帮助。除了相同的方法名称外,我们对类型B
和C
一无所知
B
和C
是否都实现了相同的接口(这意味着我们不知道它们之间的关系)问题是,我想从A调用GetSomething
,无论它是什么类型:
//Object A maybe type B or C
//both B and C can call method
//but we just don't know type of A
var result=A.GetSomething();
如果你遇到这种情况,你会怎么做?
这似乎需要一个抽象的方法
public abstract class A {
protected abstract object GetSomething();
}
在每个派生类中,您需要实现GetSomething(),例如
public class B : A {
protected override object GetSomeTHing(){
//implementation goes here
}
}
然后,您可以在实现超类(A
)的任何位置自由调用GetSomething()
如果你不是在超级类的实现中寻找调用它的方法,而是在其他地方,你基本上有三个选项
- 更改超级类的实现,以包含该方法的(潜在抽象)定义
- 使用动态键入
- 使用反射
前者与上述示例基本相同(只需使访问修饰符public
而不是protected
)
第二种和第三种选择都有相同的缺点。它们不是编译时类型的,因此在开发过程中可能偶尔会出现运行时错误,而不是编译时错误。如果你的测试覆盖率很高,那应该不会有太大问题。
我更喜欢使用动态打字,因为它比反射版更容易读写。假设GetSomething
返回一个int,它看起来像这个
int result=((dynamic)A).GetSomething();
我已经将结果更改为显式类型,而不是隐式类型,因为否则它将被类型化为dynamic
,从而导致任何涉及结果的表达式也将被动态类型化。如果你知道GetSomething
的返回类型,你最好告诉编译器前面的
- 类型B和C具有相同的名称方法GetSomething()
- 我们不知道B和C是否都实现了相同的接口
你不知道,但你能改变吗?因为最合乎逻辑的解决方案是描述接口中的"某物"行为:
interface IHasSomething
{
Something GetSomething();
}
并将其应用于B类和C类。
假设你的B和C实例被声明为object
,你可以试着测试它们是否实现了这个接口:
var something = obj as IHasSomething
if (something != null)
{
var youWereLookingFor = something.GetSomething();
}
或者,您可以尝试使用反射,这应该是与良好的OO设计相反的最后手段(如果您想添加参数和/或重载,调用另一个方法,使用不同的返回类型,等等)。
如果A
没有该方法,您就不应该考虑这样做,因为这是一个糟糕的设计,违反了OOP原则。然而,如果你绝对必须这样做,你可以尝试使用反射:
MethodInfo methodInfo = this.GetType().GetMethod("GetSomething", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
if(methodInfo != null)
result = methodInfo.Invoke(this, new object[] {});
但是,我强烈建议在A
类中使用抽象类或默认GetSomething()
。。。
在一个好的体系结构中,您可以通过接口或公共基类访问该方法。
如果你真的想/需要这样做,那么你试图做的就是鸭子打字。您可以使用dynamic
关键字或反射。
我能想到两种方法。直接检查"a"的类型是否实现了预期类型:
if(a is B)
{
((B)a).GetSomething();
}
else if(a is C)
{
((C)a).GetSomething();
}
否则,将强制转换为动态,并调用该函数。如果找不到函数,就会抛出。
dynamic dA = a;
int result;
try
{
result = dA.GetSomething();
}
catch(RuntimeBinderException ex)
{
// a was of a type that doesn't have GetSomething
}
第一个示例可以使用,第二个动态示例只能被视为示例,除非它是最后的手段。请尝试使用定义GetSomething()
的抽象类或接口。