编辑:这个问题并不能反射(reflect)我的确切情况,所以我在这里发布了一个更相关的问题: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 类型?
这是为什么,我该如何解决这个问题?
最佳答案
如果没有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);
,这样就不必重复工作。
我希望以上内容能够很好地解释该问题并提供有用的解决方法。不幸的是,如果没有更好的代码示例,很难真正理解您是如何陷入这种情况的(首先,通用方法似乎没有任何有用的方式通用,至少如示例所示)。
关于C#:带有以 Child 类型作为参数的方法的继承类:调用了错误的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33768384/