C#:带有将Child类型作为参数的方法的继承类:调用错误的方法

时间:2015-11-17 22:35:14

标签: c# generics inheritance polymorphism

编辑:此问题并未反映我的具体情况,因此我在此处发布了一个更为相关的问题: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类型呢?

为什么会这样,我该如何解决这个问题?

1 个答案:

答案 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);,这样就不需要重复工作了。

我希望上面能够很好地解释问题并提供有用的解决方法。不幸的是,如果没有更好的代码示例,很难真正理解你是如何进入这种情况的(例如,泛型方法似乎没有任何有用的通用方法,至少如示例所示)。