P-Storm
P-Storm

Reputation: 2037

c# polymorphism derive class to other derive class

I have a class for example Tile, with derive classes TileA, TileB... TileF.

Now I want always that class TileF changes with a call into TileE. And also TileE to TileD, and you can see the patern. Can I specify it directly in TileF where it changes into.

I'm looking at Activator.CreateInstance(), but this gives me a object class, and not the wanted derive class.

How can I solve this?

I do this in my Main loop, where I specified that Tile tile = TileF; then i want to do something like: tile.change() and that it changes in a new TileE

Some kind of code:

Class Tile{
   public abstract int Number{ get; }
}
Class TileF : Tile{
public override int Number
        {
            get
            {
                return 1;
            }
        }
} 
Class TileE : Tile{
public override int Number
        {
            get
            {
                return 2;
            }
        }
} 

Class Main{
Tile tile = new TileF;
//change tile to TileE
tile = tile.ToNextTileType();

}

Upvotes: 0

Views: 295

Answers (4)

P-Storm
P-Storm

Reputation: 2037

I made an error in designing TileF/TileE etc. It was good enough to make a TileN, with a property that is replacing the inner working of a tile. This way I don't have to substitute a class, and thus avoiding this problem.

Upvotes: 0

Andreas
Andreas

Reputation: 6475

There is a difference between the static and the dynamic type of an object. The static type of an object can be changed, that is you may write BaseType base = (BaseType)new DerivedType();. Changing the static type of an instance is called casting.

The compiler will restrict the call to methods, fields and properties present in the BaseType and all of its base types. The dynamic type of an object however may never change and in this case base still has the dynamic type DerivedType. The condition if (base is DerivedType) will return true in this case. You can only "change" the dynamic type by instantiating a new object of the target type and copy the desired values to the new instance. This process is called mapping.

Btw, Activator.CreateInstance will only give you an instance of the static type object, but likely with a different dynamic type. You can change the static type by casting it to a type that you know the object should have: (DerivedType)Activator.CreateInstance(typeof(DerivedType)). You can also use the generic variant, then this cast is done within the method: Activator.CreateInstance<DerivedType>(). Semantically there is no difference, except that the generic variant is easier to read.

EDIT:

Does this solve your problem?

public abstract class Tile {
  public abstract int Number { get; }
  public abstract Tile Advance();
}

public class TileA : Tile {
  public override int Number { get { return 1; } }
  public override Tile Advance() { return new TileB(); }
}

public class TileB : Tile {
  public override int Number { get { return 2; } }
  public override Tile Advance() { return new TileC(); }
}

public class TileC : Tile { ... }

You can also define the "state machine" in the abstract class like so:

public abstract class Tile {
  public abstract int Number { get; }
  public sealed Tile Advance() {
    if (this is TileA) {
      return new TileB();
    else if (this is TileB) {
      return new TileC();
    }
  }
}

Another alternative is of course to model the state machine entirely in one object:

public enum TileState { TileA, TileB, TileC };
public class Tile {
  private TileState state = TileState.TileA; // initial state

  public int Number {
    get {
      switch (state) {
        case TileState.TileA: return 1;
        case TileState.TileB: return 2;
        ...
        default: return -1; // or throw exception
      }
    }
  }

  public void Advance() {
    switch (state) {
      case TileState.TileA: state = TileState.TileB; break;
      case TileState.TileB: state = TileState.TileC; break;
      ...
      default: // exception ?
    }
  }
}

In the last example, the behavior of your object changes depending on the state variable. It's not a new instance, but it can do something completely different. I hope something of this could help.

Upvotes: 0

James Culshaw
James Culshaw

Reputation: 1057

You might want to look at interfaces. Interface lets unrelated objects be treated as the same thing when you reference a type of the Interface type e.g.

class ClassOne : ICommon;
class ClassTwo : ICommon;
class ClassThree : ICommon;

ClassOne x = new ClassOne();
ClassTwo y = new ClassTwo();
ClassThree z = new ClassThree();

List<ICommon> data = new List<ICommon>();
data.Add(x);
data.Add(y);
data.Add(z);

foreach(ICommon item in data)
{
    item.InterfaceMethodOne();
}

This might not be what you want but it is worth looking into.

James :-)

Upvotes: 0

Henk Holterman
Henk Holterman

Reputation: 273449

When TileE and TileF are siblings, ie when they derive from a common baseclass, you cannot convert them directly.

There are several possible solutions but you don't provide much detail.

I think that maybe you should not use inheritance. Could a simple enum TileType solve your problem(s)?

Upvotes: 2

Related Questions