c # полиморфизм производного класса к другому производному классу - PullRequest
0 голосов
/ 20 сентября 2011

У меня есть класс, например, Tile, с производными классами TileA, TileB ... TileF.

Теперь я хочу всегда, чтобы класс TileF изменялся при вызове в TileE.А также TileE в TileD, и вы можете увидеть патерн.Могу ли я указать его непосредственно в TileF, где он меняется на.

Я смотрю на Activator.CreateInstance(), но это дает мне класс объекта, а не требуемый класс наследования.

Как можноЯ решаю это?

Я делаю это в своем цикле Main, где я указал, что Tile tile = TileF;, тогда я хочу сделать что-то вроде: tile.change() и что это изменится в new TileE

Какой-то код:

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();

}

Ответы [ 4 ]

2 голосов
/ 20 сентября 2011

Когда TileE и TileF являются братьями и сестрами, т.е. когда они являются производными от общего базового класса, вы не можете преобразовать их напрямую.

Существует несколько возможных решений, но вы нене предоставлю подробностей.

Я думаю, что, возможно, вам не следует использовать наследование.Может ли простой enum TileType решить ваши проблемы?

0 голосов
/ 21 сентября 2011

Я допустил ошибку при разработке TileF / TileE и т. Д. Достаточно было создать TileN со свойством, которое заменяет внутреннюю работу плитки. Таким образом, мне не нужно подменять класс и, таким образом, избежать этой проблемы.

0 голосов
/ 20 сентября 2011

Существует различие между статическим и динамическим типом объекта. Статический тип объекта может быть изменен, то есть вы можете написать 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 ?
    }
  }
}

В последнем примере поведение вашего объекта изменяется в зависимости от переменной состояния. Это не новый экземпляр, но он может сделать что-то совершенно другое. Надеюсь, что-то из этого может помочь.

0 голосов
/ 20 сентября 2011

Возможно, вы захотите взглянуть на интерфейсы. Интерфейс позволяет рассматривать несвязанные объекты как одно и то же, когда вы ссылаетесь на тип типа Интерфейс, например

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();
}

Это может быть не то, что вы хотите, но это стоит посмотреть.

Джеймс: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...