在我的日常工作期间,我遇到了一个问题:
假设:
Object
类型B
或输入C
B
和C
具有相同的名称方法GetSomething()
B
和C
是否实现了相同的接口(这意味着我们不知道它们之间的关系)B
和C
继承自Object
,这意味着没有任何帮助。除了相同的方法名称,我们对类型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();
如果你遇到这种情况,你会做什么?
答案 0 :(得分:3)
这似乎是一种抽象的方法
public abstract class A {
protected abstract object GetSomething();
}
在每个派生类中,您需要实现GetSomething(),例如
public class B : A {
protected override object GetSomeTHing(){
//implementation goes here
}
}
然后你可以在超类(GetSomething()
)的实现中随意调用A
如果你不想在超级类的实现中调用它,但在其他地方你基本上有三个选项
前者基本上与上面的示例相同(只需设置访问修饰符public
而不是protected
)
第二和第三选择都遭受同样的下行。它们不是键入的编译时间,因此您可能(将)在开发期间偶尔会有运行时错误而不是编译时错误。如果你有一个高测试覆盖率,但不应该是一个问题。
我更喜欢使用动态类型,因为它比反射版更容易阅读和编写。假设GetSomething
返回一个int,它看起来像这个
int result =((dynamic)A)。GetSomething();
我将结果更改为显式类型而不是隐式类型,因为否则将其键入为dynamic
,导致任何涉及结果的表达式也将被键入动态。如果您知道GetSomething
的返回类型,那么最好先告诉编译器
答案 1 :(得分:1)
- 类型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();
}
或者你可以尝试使用Reflection,它总是应该是最后的手段而不是优秀的OO设计(如果你想添加参数和/或重载,调用另一种方法,使用不同的返回类型等等)
答案 2 :(得分:0)
如果A
没有这种方法,你就不应该考虑这样做,因为这是糟糕的设计和反对OOP原则。但是,如果你绝对必须这样做,你可以尝试使用反射:
MethodInfo methodInfo = this.GetType().GetMethod("GetSomething", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
if(methodInfo != null)
result = methodInfo.Invoke(this, new object[] {});
但是我强烈建议您在GetSomething()
课程中使用抽象类或使用默认A
...
答案 3 :(得分:0)
我能想到的两种方式。直接检查'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()
的抽象类或接口。
答案 4 :(得分:0)
在一个好的架构中,您可以通过接口或公共基类访问该方法。
如果您真的想要/需要,那么您要做的就是 duck typing 。您可以使用dynamic
关键字或反射。