简体   繁体   中英

Calling a ClassA.Method() as ClassB.Method() but only affecting ClassA values, both classes are deriving from the same BaseClass

In this example I am building an automation library for browsers. There is a base class called Mouse, and derived classes called RoboticMouse and HumanMouse.

Lets say I instantiate the mouse as HumanMouse but in one specific occasion I want it to behave as a RoboticMouse, for example, on parts where I need it to move the mouse faster, what I tried doing is:

Mouse m = new HumanMouse();
m.Move();
(m as RoboticMouse).Move();

But I get a NullReferenceException since the Mouse m was initialized as a HumanMouse and not a RoboticMouse.

I could do:

Mouse m = new HumanMouse();
m.Move();
m = new RoboticMouse(); m.Move();

But this way the values inside it would be re-initialized and I want to keep the state intact, for example, for tracking the mouse position.

EDIT: Simpler example:

This does not work as instance is ClassB, and throws null.

public class Program
{
    public static void Run()
    {
        BaseClass instance = new ClassB();

        instance.Increment();
        Console.WriteLine(instance.Value);

        (instance as ClassA).Increment();
        Console.WriteLine(instance.Value);

        Console.ReadLine();
    }
}

class BaseClass
{
    public int Value { get; set; }

    public virtual void Increment()
    {
        Value++;
    }
}

class ClassA : BaseClass
{
    public override void Increment()
    {
        Value += 2;
    }
}

class ClassB : BaseClass
{
    public override void Increment()
    {
        Value += 4;
    }
}

If I follow the suggestion given making ClassB inherit from ClassA:

class ClassB : ClassA
{
    public override void Increment()
    {
        Value += 4;
    }
}

And try to cast it:

public static void Run()
    {
        BaseClass instance = new ClassB();

        instance.Increment();
        Console.WriteLine(instance.Value);

        (instance as ClassA).Increment();
        Console.WriteLine(instance.Value);

        Console.ReadLine();
    }

It still runs ClassB version of the method...

The compiler does not know how to conver from HumanMouse to RoboticMouse .

When you are using new you are creating effectively a new reference with new values, so it makes sense to see what you see.

Two ways around it. If a HumanMouse is indeed a RoboticMouse , then extend the HumanMouse from the RoboticMouse

If the HumanMouse is castable to a RoboticMouse , then you can declare how the cast is made by using the user-defined-conversion-operators .

Edit based on question edits

Let me give you an example with animals.

Let's say that ClassA is an animal and ClassB is a Cat. So the Cat extends the animal and set a new behavior for the Move function.

The cat will always be an animal, but not every animal is a cat. That's why

// This works
Animal a = new Cat();
// This does not work
Cat a = new Animal();

Now when you assign a cat to an animal and you have overriden the Move function, that means that the cat will always move as a cat whether or not you access it as an animal. You can't cast a cat to an animal as it is already an animal. (cat as Animal) does nothing.

Same way you can't cast classB to classA since B is already an A and will always behave as a B.

Edit 2: Possible solution

public abstract class Mouse {

    public int x {get; set;}
    public int y {get; set;}

    public Mouse(x,y) {
        this.x = x;
        this.y = y;
    }

    public virtual void Move() {
        this.x++;
        this.y++;
    }

    public virtual void Move(x, y) {
        this.x+= x;
        this.y+= y;
    }
}

public class HumanMouse: Mouse {
   // whatever
   public HumanMouse(): base(1,1) {
   }
}

public class RoboticMouse: Mouse {
   public static int
   // whatever
   public RoboticMouse(): base(2,2) {
   }
}


Mouse m = new HumanMouse();
m.Move();
m.Move(1,2); 
// or
Mouse m2 = new RoboticMouse();
m.Move();
m.Move(m2.x,m2.y); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM