9

I have these two main classes. First the FSMSystem class:

public class FSMSystem<T> : MonoBehaviour where T : FSMSystem<T>
{
    private T m_Owner = default(T);

    protected FSMState<T> currentState;

    private Dictionary<int, FSMState<T>> m_states;

    public FSMSystem(T owner)
    {
        m_Owner = GameObject.FindObjectOfType(typeof(T)) as T; //owner;
        m_states = new Dictionary<int, FSMState<T>>();
    }

    protected void AddState( FSMState<T> state )
    {
        m_states.Add( state.GetStateID(), state );
    }
}

And the second class, FSMState:

public abstract class FSMState<T>
{   
    public abstract int GetStateID();

    public abstract void OnEnter (FSMSystem<T> fsm, FSMState<T> prevState);
    public abstract void OnUpdate (FSMSystem<T> fsm);
    public abstract void OnExit (FSMSystem<T> fsm, FSMState<T> nextState);
}

It leads to the following error:

error CS0309: The type 'T' must be convertible to 'FSMSystem<T>' in order to use it as parameter 'T' in the generic type or method 'FSMSystem<T>'

Can someone tell me how to resolve this? I see many other posts similar to this one but I'm not seeing the relationship.

g t
  • 7,287
  • 7
  • 50
  • 85
Claire Lee
  • 113
  • 1
  • 1
  • 4
  • which code leads to this error? – cuongle May 22 '13 at 07:28
  • I agree, why don't you remove the constraint all together? The code seems to compile fine without it. – NeddySpaghetti May 22 '13 at 07:40
  • @J.Steen That could be an (the) answer, methinks. – Onots May 22 '13 at 07:41
  • @Onots While I'm usually disinclined to give answers that are (albeit cryptically) explained by the compiler errors, I'll give it a crack. – J. Steen May 22 '13 at 07:42
  • @J.Steen - in C++, it's called the Curiously Recurring Template Pattern. Eric Lippert has a blog post about it called [Curiouser and curiouser](http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx) where he points out that it's a flawed approach in C# (but it's perfectly compilable) – Damien_The_Unbeliever May 22 '13 at 07:44
  • @Damien_The_Unbeliever Thank you for a name to put to the construct. I agree it's flawed, I agree the code - as it stands - can be compiled, but can it actually **be used** in C#? Can you instantiate a class of type `FSMSystem`? – J. Steen May 22 '13 at 07:46
  • 3
    Consider `class MyFSM : FSMSystem{}` You can't directly instantiate a `FSMSystem`, but you can instantiate a class that *derives* from it. – Damien_The_Unbeliever May 22 '13 at 07:48
  • @Damien_The_Unbeliever D'oh. I've even USED that construct. It was so long ago that I completely forgot. – J. Steen May 22 '13 at 08:02

2 Answers2

10

The T of FSMState must also be constrained, otherwise it cannot be used as the T of FSMSystem - which has constraints placed on it (T : FSMSystem<T>).

If you would have provided the line number of the compiler error, I suspect it would point to the methods OnEnter, etc.

flq
  • 22,247
  • 8
  • 55
  • 77
  • the errors occurred these lines. public abstract void OnEnter (FSMSystem fsm, FSMState prevState); public abstract void OnUpdate (FSMSystem fsm); public abstract void OnExit (FSMSystem fsm, FSMState nextState); – Claire Lee May 23 '13 at 00:43
  • This was helpful for me, I put the constraint right after the class name instead of the interfaces – MichaelChan May 13 '19 at 04:58
0

It's big help to me. thank you all. I resolved the problem. I misunderstood about 'where' syntax.

Here is the revised version that works.

public class FSMSystem<T> : MonoBehaviour where T : FSMSystem<T>
{
    private T m_Owner = default(T);

    protected FSMState<T> currentState;

    private Dictionary<int, FSMState<T>> m_states;

    public FSMSystem()
    {
        m_Owner = this as T;
        m_states = new Dictionary<int, FSMState<T>>();
    }

    protected void AddState( FSMState<T> state )
    {
        m_states.Add( state.GetStateID(), state );
    }
}


public abstract class FSMState<T> where T : FSMSystem<T>
{
    public abstract int GetStateID();

    public abstract void OnEnter (T fsm, FSMState<T> prevState);
    public abstract void OnUpdate (T fsm);
    public abstract void OnExit (T fsm, FSMState<T> nextState);
}
Guvante
  • 18,775
  • 1
  • 33
  • 64
Claire Lee
  • 113
  • 1
  • 1
  • 4