编辑:此问题并未反映我的具体情况,因此我在此处发布了一个更为相关的问题:Inherited class with methods taking Child type as a parameter: wrong method being called
我有一个问题,我在解决问题时遇到了一些麻烦。
我有一个类型为BaseClass的父类,它有一个采用BaseClass参数的方法:
public void copyAttributes(BaseClass bc){
//Copy the attributes from bc to this class
}
我还有一个名为ChildClass的继承类型,它有一个同名的方法,它接受一个类型为ChildClass的参数。
public void copyAttributes(ChildClass cc){
//Copy the attributes from cc to this class
}
我在调用方法的方法中使用泛型:
public void Foo<T>(...,T objectToCopy, ...) where T : BaseClass{
ChildClass thisObject = new ChildClass();
thisObject.copyAttributes(..., objectToCopy, ...);
Console.writeline(thisObject.printAllAttributes());
}
但是,如果我这样称呼它:
Foo<ChildClass>(..., new ChildClass(...), ...);
它运行父类的方法,而不是子类的方法,因此不会设置特定于子类的属性。
我不明白这一点,我传递了一些特别是ChildClass类型的东西,为什么它决定使用BaseClass类型呢?
为什么会这样,我该如何解决这个问题?
答案 0 :(得分:2)
如果没有可靠地再现问题的a good, minimal, complete code example,很难完全理解你的问题。做一些推论,我猜想一个合适的代码示例实际上看起来像这样:
class A
{
public void M(A a) { Console.WriteLine("A.M"); }
}
class B : A
{
public void M(B a) { Console.WriteLine("B.M"); }
}
class Program
{
static void Main(string[] args)
{
B b = new B();
M(b);
}
static void M<T>(T t) where T : A
{
B b = new B();
b.M(t);
}
}
特别要注意泛型方法void M<T>(T t) where T : A
的约束。这是为了甚至能够编译代码所必需的。
现在,就你所看到的行为而言:重要的是要记住重载解析是在编译时发生的事情。编译器必须根据当时可用的信息选择要调用的方法。
在您的通用方法中,您告诉它的所有内容都是参数t
必须是A
类型。它可能是更多派生的类型,但编译器可以依赖的是它是A
。因此,它必须选择它知道肯定有效的过载;即A
中的方法。
那么,该怎么办呢?
嗯,最简单的解决方法是使调用方法动态而不是泛型:
static void M(dynamic t)
{
B b = new B();
b.M(t);
}
这样做会强制重载解析的编译步骤在运行时而不是编译时进行。当然,在运行时,编译器知道要使用的类型。
请注意,这确实涉及在运行时基本上编译该部分代码,这是额外的开销。如果您可以稍微更改类的声明,则可以使用多态来产生相同的效果:
class A
{
public virtual void M(A a) { Console.WriteLine("A.M"); }
}
class B : A
{
public override void M(A a) { Console.WriteLine("B.M"); }
}
当然,B.M(A)
可以将参数a
强制转换为B
类型,以便访问B
中的成员(当然,调用者必须确保它传递一个相应类型的对象),B.M(A)
甚至可以调用基类实现(即base.M(a);
,这样就不需要重复工作了。
我希望上面能够很好地解释问题并提供有用的解决方法。不幸的是,如果没有更好的代码示例,很难真正理解你是如何进入这种情况的(例如,泛型方法似乎没有任何有用的通用方法,至少如示例所示)。