Существует различие между статическим и динамическим типом объекта. Статический тип объекта может быть изменен, то есть вы можете написать BaseType base = (BaseType)new DerivedType();
. Изменение статического типа экземпляра называется casting .
Компилятор ограничит вызов методов, полей и свойств, представленных в BaseType
, и всех его базовых типов. Однако динамический тип объекта может никогда не измениться, и в этом случае base
все еще имеет динамический тип DerivedType
. Условие if (base is DerivedType)
в этом случае вернет true. Вы можете «изменить» только динамический тип, создав новый объект целевого типа и скопировав нужные значения в новый экземпляр. Этот процесс называется mapping .
Кстати, Activator.CreateInstance
даст вам только экземпляр статического типа object
, но, скорее всего, с другим динамическим типом. Вы можете изменить статический тип, приведя его к типу, который, как вы знаете, должен иметь объект: (DerivedType)Activator.CreateInstance(typeof(DerivedType))
. Вы также можете использовать универсальный вариант, тогда это приведение выполняется в методе: Activator.CreateInstance<DerivedType>()
. Семантически нет никакой разницы, за исключением того, что общий вариант легче читать.
EDIT:
Решает ли это вашу проблему?
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 { ... }
Вы также можете определить «конечный автомат» в абстрактном классе следующим образом:
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();
}
}
}
Другой альтернативой, конечно, является моделирование конечного автомата целиком в одном объекте:
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 ?
}
}
}
В последнем примере поведение вашего объекта изменяется в зависимости от переменной состояния. Это не новый экземпляр, но он может сделать что-то совершенно другое. Надеюсь, что-то из этого может помочь.