我有以下类层次结构:
class A {
/// stuff
}
class B : A {
/// stuff
}
class C<T> : B {
/// stuff
}
然后在某处完全不同我有以下三种方法:
public void foo(A a) {
}
// overload 1
public void bar(B b) {
}
// overload 2
public void bar<T>(C<T> ct) {
}
现在,无论出于何种原因,我需要在给定A的实际类型的情况下从foo调用“正确”栏。也就是说,如果A实际上是B类型,我需要调用重载1并且如果A实际上是类型C(无论T可能是什么),我需要调用重载2.并且为了完整性,如果A不是B或C,则什么都不做。
现在,我正在使用Type类的IsAssignableFrom方法来决定是否可以向上转换为B:
public void foo(A a) {
if (typeof(B).IsAssignableFrom(a)) {
bar((B)a);
}
}
但这也涉及C变种。所以问题是,我该如何执行此向上播放?反射?动力学?我们使用的是.NET 4,所以在C#5中引入的任何东西都是我无法使用的。
答案 0 :(得分:6)
然后在某处完全不同我有以下三种方法:
这说明了问题的第一个潜在解决方案。不要“完全不同的地方”。让bar
成为A
的虚拟成员并让foo
调用它。
第二种可能的解决方案是使用访客模式。
interface IVisitor
{
void Visit(B b);
void Visit<T>(C<T> c);
}
class A
{
public virtual void Accept(IVisitor v)
{ } // Do nothing
}
class B : A
{
public override void Accept(IVisitor v)
{ v.Visit(this); }
}
class C<T> : B
{
public override void Accept(IVisitor v)
{ v.Visit<T>(this); }
}
class P
{
class Visitor : IVisitor
{
public void Visit(B b) { bar(b); }
public void Visit<T>(C<T> c) { bar<T>(c); }
}
public static bar(B b) { }
public static bar<T>(C<T> c) { }
public static void foo(A a)
{
a.Accept(new Visitor());
}
}
但我们假设您无法修改A
,B
或C<T>
。
现在,无论出于何种原因,我需要在给定A的实际类型的情况下从foo调用“正确”栏。也就是说,如果A实际上是B类型,我需要调用重载1并且如果A实际上是类型C(无论T可能是什么),我需要调用重载2.并且为了完整性,如果A不是B或C,则什么都不做。
第一个很简单:
public void foo(A a)
{
if (a is B) bar((B)a);
然而,通用子类型很难;遗憾的是,if (a is C<?>) bar((C<?>)a;
没有机制。
你要与反射或dynamic
有关。请注意,如果dynamic
无法在运行时找到匹配的bar
,那么它将抛出,而不会执行任何操作。
答案 1 :(得分:3)
使用dynamic
。它将使方法解析在运行时而不是编译时发生,因此您将获得最适合实际实例类型的方法。
bar((dynamic)value);