C#泛型,交叉引用状态模式的类

ElD*_*ino 8 c# generics

我试图进入C#泛型并创建了一个状态模式的状态机,现在我尝试重构.

我有一个状态,它引用了它正在处理的对象.

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

    protected T statefulObject;

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

}
Run Code Online (Sandbox Code Playgroud)

我有一个有状态的对象,这应该引用它的当前状态.

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

    public T state;

}
Run Code Online (Sandbox Code Playgroud)

但它不起作用("类型不能用作泛型类型或方法中的类型参数't').

我想要实现的是这样的:

public class Monster : StatefulObject<MonsterState> {

}

public abstract class MonsterState : AbstractState<Monster> {

}
Run Code Online (Sandbox Code Playgroud)

这可能吗?如果不是这样,还有另一个吗?谢谢.

Luc*_*ski 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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

这是否真的是一个好主意值得怀疑,这样的代码可能太混乱了。


您还可以采用更简单(但类型不太强)的方法:

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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

这并不能确保您无法分配,例如 aPlayerState到 a Monster,您应该在运行时检查。