【问题标题】:How to call my concrete class method when I keep calling the base class method当我不断调用基类方法时如何调用我的具体类方法
【发布时间】:2015-08-20 07:54:40
【问题描述】:

鉴于这些类:

public abstract class Car
{
    public void Copy(Car car)
    {
        // stuff //
    }
}

public class Ford : Car
{
    public void Copy(Ford updatedFord) 
    {
        base.Copy(updatedFord);
        // copy ford stuff //
    }
}

public class Holden  : Car
{
    public void Copy(Holden updatedHolden) { .. }
}

这就是我想要做的......

public void TestMethod()
{
    Car car1 = new Ford { Colour = "Red", StickerCount = 1 };
    Car car2 = new Ford { Colour = "Blue", StickerCount = 666 };

    car1.Copy(car2);
    // I expect blue AND 666 to be copied. only Blue is.
}

Here's all the code in a .NET FIDDLE.

因此,在这种情况下,如果汽车是Ford 实例,则调用Ford 类上的Copy(..) 方法......而不是Car 实例上的复制方法。

我只是不确定如何在最具体的类上调用 Copy 方法(然后通过继承的层次结构调用 base.XXX()

【问题讨论】:

  • 制作virtual CopyAggreagateRoot 方法并从继承的类中覆盖它。小提琴 => dotnetfiddle.net/NYKAyv
  • @MitatKoyuncu 现在你在每个“关卡”中进行投射。例如。 Colour = ((Car)car).Colour;
  • 在您的情况下,您有静态绑定,即编译时间,因为您的方法是非虚拟的。当您确定它们是Ford 时,为什么要将实例声明为Car
  • 根据您的设计,可以将霍顿汽车复制到福特汽车。这是正确的设计吗?!

标签: c# .net inheritance


【解决方案1】:

这是因为Ford.Copy 未在基类上声明,因此在将Ford 转换为Car 后无法访问。

Ford.Copy 需要覆盖Car.Copy

但是由于它的参数有不同的类型,它不能只覆盖基方法。

您需要参数化Car - Car<TCar> - 然后使用该类型参数来定义您的参数类型。然后每个子类将指定他们将复制的汽车类型。

这叫F-bound polymorphism

public abstract class Car<TCar> where TCar : Car<TCar>
{
    public virtual void Copy(TCar car)
    {
        // stuff //
    }
}


public class Ford : Car<Ford>
{
    public override void Copy(Ford updatedFord) {}
}

public class Holden  : Car<Holden>
{
    public override void Copy(Holden updatedHolden) { .. }
}

【讨论】:

  • 你在哪里看到隐藏(遮蔽)基类成员?
  • @HamletHakobyan 啊,你是对的,不是隐藏它,而是超载。不能从基类访问。我会修改这个细节。
  • 有没有办法避免将泛型放在class 上,而是放在单一方法上?
  • @Pure.Krome 不幸的是,没有:/ 如果方法是通用的,那么 Ford 将不得不处理复制任何汽车。您将无法将 Ford.Copy 限制为仅限福特汽车。
  • 我发现T : Car&lt;T&gt; 是多余的,但想不出更好的方法。 +1
【解决方案2】:

这会给你你想要的行为:

    dynamic car1 = (Car)new Ford { Id = 1, Colour = "Red", StickerCount = 1 };
    dynamic car2 = (Car)new Ford { Id = 2, Colour = "Blue", StickerCount = 666 };

【讨论】:

  • 用动态编译的代码污染你的代码库来解决这样一个简单的问题会造成混乱。
  • 为此目的忘记动态。你见过使用动态时会编译出什么样的代码吗?更不用说糟糕的表现了。
【解决方案3】:

这里没有“隐藏”。他正在超载Car.Copy(Car)。 这应该可以帮助您找到自己。

using System;

class A
{
    public void Foo(A a)
    {
        Console.WriteLine("A.Foo");
    }
}

class B : A
{
    //overloading
    public void Foo(B b)
    {
        Console.WriteLine("Overload");
    }

    //hiding
    public new void Foo(A a)
    {
        Console.WriteLine("Hide");
    }
}

class Test
{
    static void Main()
    {
        A a = new A(); 
        A b = new B();
        B c = new B();

        a.Foo(a);   //A.foo

        b.Foo(a);   //A.foo
        b.Foo(b);   //A.foo
        ((dynamic) b).Foo(a); //hide (equivalent to overriding Foo in B when A.Foo is virtual or abstract)

        c.Foo(a);   //hide
        c.Foo(b);   //hide
        c.Foo(c);   //overload
    }
}

【讨论】:

    【解决方案4】:

    您的 Copy 方法应该是虚拟的。

    public abstract class Car
    {
        public string Colour { get; set; }
    
        public virtual void Copy(Car car)
        {
            Colour = car.Colour;
        }
    }
    
    public class Ford : Car
    {
        public int StickerCount { get; set; }
    
        public override void Copy(Car car) 
        {
            base.Copy(car);
            Ford ford = car as Ford;
            if (ford != null)
                StickerCount = ford.StickerCount;    
        }
    }
    
    public static void Main()
    {
        Car car1 = new Ford { Colour = "Red", StickerCount = 1 };
        Car car2 = new Ford { Colour = "Blue", StickerCount = 666 };
    
        // if Copy is not virtual, Car.Copy will be called here instead of Ford.Copy!
        car1.Copy(car2);
    
        Console.WriteLine("Result should be blue: " + car1.Colour);
        Console.WriteLine("Result should be 666: " + ((Ford)car1).StickerCount);
    }
    

    【讨论】:

    • 如果car 不是Ford 怎么办?你抛出异常吗?您正在放弃静态检查。
    • 这取决于设计。通用解决方案可以仅从相同类型进行复制,这是可以预期的。此解决方案复制任何汽车类型的可能属性,这也可以是预期设计。
    • Err... 有什么理由拒绝投票?
    【解决方案5】:

    您必须将 Car.Copy 声明为虚拟,并将 Ford.Copy 声明为覆盖。那么它应该可以工作了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-17
      • 2021-05-13
      • 1970-01-01
      • 1970-01-01
      • 2011-08-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多