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

标签 c# generics inheritance polymorphism

编辑:这个问题并不能反射(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/

相关文章:

c# - 在 foreach 循环中形成不将模型发布回 Controller

c# - 如何将 HtmlAgilityPack 添加到 Visual Studio 2010 项目中

Java名称冲突错误,一个方法与另一个方法有相同的删除

function - Typescript 中的通用函数和推断通用键

java - int 与 int[] 区别 - 泛型内部自动装箱?

ruby-on-rails - 如何在 Rails 3.1 中复制 class_inheritable_accessor 的行为?

c# - 在 C# 中从基构造函数调用子类构造函数

C# COMException 读取 MSWord Shape 对象 Microsoft.Office.Interop.Word 的属性

c# - 在 C# 中查找包含超过 20,000 个文件的目录中的文件的最快方法

java - instanceof 和泛型的编译错误