0

在我的日常工作中,我遇到了一个问题:

认为:

  1. 我们有一个对象A,它的Object类型
  2. 一个可能的类型B或类型C
  3. 类型BC具有相同名称的方法GetSomething()
  4. 我们不知道两者是否B实现C相同的接口(这意味着我们不知道它们之间的关系)
  5. 类型BC继承从中Object没有任何帮助。B除了相同的方法名,我们对类型和类型一无所知C

问题是,我想GetSomething从 A 调用,无论它是什么类型:

//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();

如果你遇到这种情况,你会怎么做?

4

5 回答 5

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

第 2 和第 3 选项都有相同的缺点。它们不是编译时类型的,因此您可能(将)在开发过程中偶尔出现运行时错误而不是编译时错误。如果您的测试覆盖率很高,那应该不是太大的问题。

我更喜欢使用动态类型,因为它比反射版本更容易读写。假设GetSomething返回一个 int 它看起来像这样

int result = ((dynamic)A).GetSomething();

我已将 result 更改为显式类型而不是隐式类型,因为否则它将被键入,dynamic从而导致任何涉及 result 的表达式也被键入为动态类型。如果您知道返回类型,GetSomething最好提前告诉编译器

于 2013-06-28T11:48:17.460 回答
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();
}

或者您可以尝试使用反射,它始终应该是最后的手段,而不是良好的 OO 设计(如果您想添加参数和/或重载、调用另一个方法、使用不同的返回类型等等)。

于 2013-06-28T11:55:09.603 回答
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类中使用默认值...

于 2013-06-28T11:55:00.857 回答
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()

于 2013-06-28T11:56:22.790 回答
0

在良好的体系结构中,您可以通过接口或公共基类访问方法。

如果你真的想要/需要那个,那么你要做的就是所谓的鸭子打字。您可以使用dynamic关键字或反射。

于 2013-06-28T11:58:24.823 回答