2015-06-13 3 views
8

Я пытаюсь попасть в генераторы C# и создал конечный автомат с шаблоном состояния, и теперь я пытаюсь реорганизовать.C# generics, перекрестные ссылочные классы для шаблона состояния

У меня есть состояние, в котором есть ссылка на объект, над которым он работает.

public abstract class AbstractState<T> where T : StatefulObject { 

    protected T statefulObject; 

    public AbstractState(T statefulObject) { 
     this.statefulObject = statefulObject; 
    } 

} 

и у меня есть объект, который имеет состояния, это должно иметь ссылку на его текущее состояние.

public abstract class StatefulObject<T> : MonoBehaviour where T : AbstractState<StatefulObject<T>> { 

    public T state; 

} 

Но это не работает («тип не может быть использован в качестве параметра типа„Т“в универсальном типе или методе»).

То, что я хочу достичь, это что-то вроде этого:

public class Monster : StatefulObject<MonsterState> { 

} 

public abstract class MonsterState : AbstractState<Monster> { 

} 

Возможно ли это? Если это не так, есть ли другое? Спасибо.

+0

Как вы объявляете 'StatefulObject' как общий тип (2-й фрагмент) и используете его как не общий тип (первый фрагмент)? –

ответ

3

Вы можете злоупотребления интерфейсов и дисперсия для достижения этой цели:

public interface IState<out TObject, in TState> 
    where TObject : IStatefulObject<TObject, TState> 
    where TState : IState<TObject, TState> 
{ 
} 

public interface IStatefulObject<in TObject, out TState> 
    where TObject : IStatefulObject<TObject, TState> 
    where TState : IState<TObject, TState> 
{ 
} 

public abstract class AbstractState<TObject> : IState<TObject, AbstractState<TObject>> 
    where TObject : IStatefulObject<TObject, AbstractState<TObject>> 
{ 
    protected TObject Object { get; private set; } 

    public AbstractState(TObject obj) 
    { 
     Object = obj; 
    } 
} 

public abstract class StatefulObject<TState> : IStatefulObject<StatefulObject<TState>, TState> 
    where TState : IState<StatefulObject<TState>, TState> 
{ 
    protected TState State { get; set; } 
} 

public class Monster : StatefulObject<MonsterState> 
{ 
    public Monster() 
    { 
     State = new IdleMonsterState(this); 
    } 
} 

public abstract class MonsterState : AbstractState<Monster> 
{ 
    protected MonsterState(Monster monster) 
     : base(monster) 
    { 
    } 
} 

public class IdleMonsterState : MonsterState 
{ 
    public IdleMonsterState(Monster monster) 
     : base(monster) 
    { 
    } 
} 

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


Вы могли бы также пойти с более простым (но менее сильно типизированных) подход:

public abstract class AbstractState 
{ 
} 

public abstract class StatefulObject 
{ 
} 

public abstract class AbstractState<TObject> : AbstractState 
    where TObject : StatefulObject 
{ 
    protected TObject Object { get; private set; } 

    public AbstractState(TObject obj) 
    { 
     Object = obj; 
    } 
} 

public abstract class StatefulObject<TState> : StatefulObject 
    where TState : AbstractState 
{ 
    protected TState State { get; set; } 
} 

public class Monster : StatefulObject<MonsterState> 
{ 
} 

public abstract class MonsterState : AbstractState<Monster> 
{ 
    protected MonsterState(Monster monster) 
     : base(monster) 
    { 
    } 
} 

Это не гарантирует, что Вы не сможете назначить, скажем, PlayerState к Monster , вы должны проверить это во время выполнения.

+0

Одним из недостатков этого дизайна является то, что вы можете назначить Monster любое состояние не ограничено тем, что состояние MonsterState –

+0

@MarcCals да, я фактически неправильно понял цель OP. Я переписал ответ. –

+0

@LucasTrzesniewski Это работает. Мне нужно некоторое время, чтобы увидеть это :) Сначала компилятор жаловался на вход и выход в интерфейсах, и мне пришлось установить цель на .net4.0 (я работаю с Unity). Спасибо :) – ElDuderino

Смежные вопросы