Создание псевдонима типа, вытекающего из общего класса в C #

Ross Lombardi спросил: 13 июня 2018 в 10:04 в: c#

У меня есть класс с некоторыми общими параметрами, из-за чего больно печатать в десятках классов, в которых он используется.

public abstract class StateBase<StatesList, StateData>
    where StatesList : class
    where StateData : class
{
    public string Name { get; protected set; }
    protected StatesList stateList;
    protected StateData stateData;    public StateBase(StatesList stateList, StateData stateData)
    {
        Name = this.GetType().Name;
        this.stateList = stateList;
        this.stateData = stateData;
    }    public abstract bool CanTransitionTo(StateBase<StatesList, StateData> newState);
    public abstract void Enter();
    public abstract StateBase<StatesList, StateData> Tick();
    public abstract void Exit();
}

Я знаком с функцией typedef C / C ++ и скорее пропущу ее прямо сейчас. Я знаю, что ближайшая функция C # - это "использование" директивы, позволяющая сделать псевдоним ограниченным одним файлом. Я могу просто вернуться к тому, что это не так, но пока эти классы продолжают меняться, и мне хотелось бы немного побольше огня и забыть. Итак, я попытался решить проблему с псевдонимом немного больше элегантно, создав новый класс, который вытекает из вышеперечисленного класса, со всеми заполненными параметрами.

public abstract class AIState : StateMachine.StateBase<UnitAIStateList, AIStateData>
{
    public abstract override bool CanTransitionTo(AIState newState);
    public abstract override void Enter();
    public abstract override void Exit();
    public abstract override new AIState Tick();
}

Как вы можете догадаться, C # не позволял мне сойти с рук, что без труда. Базовый класс Tick() возвращает общую версию. Мой производный класс заменяет фактические типы. Похоже, что он должен работать, поскольку AIState - это тип того же самого вопроса, который он запрашивает:

'AIState.Tick()': return type must be 'StateBase<UnitAIStateList, AIStateData>' to match overridden member 'StateBase<UnitAIStateList, AIStateData>.Tick()'

Я подозреваю, что причина, по которой это происходит, заключается в том, что C # реализуйте ковариацию типов, особенность, с которой я не очень хорошо знаком. Но, как бы то ни было, я недостаточно знаком с этим, чтобы действительно знать, не объясняет ли это мое объяснение.

2 ответа

Ross Lombardi ответил: 13 июня 2018 в 11:46
Функция Tick () может возвращать новое состояние для перехода. Я подумал об изменении этого вопроса, учитывая, что теперь у него есть жесткое ограничение, которое было снято в другом месте, но я бы подумал, что это не имеет никакого отношения к вопросу, поскольку такая же проблема существует с CanTransitionTo. Это часть государственной машины, используемой для управления ИИ в шутере от первого лица. StateBase - общая структура для всех состояний.
Dan Rayson ответил: 13 июня 2018 в 11:27

Несколько вещей;

1) Я бы решил, что ваш выбор потребует результата типа StateBase<StatesList, StateData> из вашего метода Tick. Каков абсолютный минимальный тип, который вам нужно использовать? Будет ли object достаточно?

2) Если вам действительно требуется возвращаемое значение типа "такой же, как тип", вам придется используйте generics круговым способом, например:

public abstract class StateBase<StatesList, StateData, TChildType>
 where StatesList : class
 where StateData : class
 where TChildType : StateBase<StatesList, StateData, TChildType> //notice addition of TChildType
{
    public string Name { get; protected set; }
    protected StatesList stateList;
    protected StateData stateData;    public StateBase(StatesList stateList, StateData stateData)
    {
        Name = this.GetType().Name;
        this.stateList = stateList;
        this.stateData = stateData;
    }    public abstract bool CanTransitionTo(TChildType newState);
    public abstract void Enter();
    public abstract TChildType Tick();
    public abstract void Exit();
}public class DerivedState : StateBase<string, string, DerivedState>
{
    ...
}
Dan Rayson ответил: 14 июня 2018 в 12:58
@RossLombardi Видя, как вы используете шаблон StateMachine, могу ли я пойти по небольшому касанию и предложить использовать пакет nuget для конечного автомата Stateless. Он предоставит вам простой способ настройки состояний машин и обработки переходов и т. Д. Просто мысль. Есть, конечно, и другие рамки StateMachine ^^

Дополнительное видео по вопросу: Создание псевдонима типа, вытекающего из общего класса в C #

Псевдонимы для запуска программ с помощью VoiceButton

01. Придумываем псевдоним

G Suite от Google: Единое информационное пространство для распределенных офисов