In first time, sorry for my bad english language …
So, my problem is a syntax C# problem.
In fact, I have two template mother class, and several daughter class.
I show you (this code works) :
First mother class:
public class FSM<T> : MonoBehaviour
where T : class
{
protected State<T> m_CurrentState = null;
[...]
public void ChangeState<NewState>() where NewState : State<T>, new()
{
if(m_CurrentState != null)
{
m_CurrentState.End();
}
m_CurrentState = new NewState();
m_CurrentState.SetFSM( this as T );
m_CurrentState.Start();
}
[...]
}
Second mother class :
public class State<T>
where T : class
{
protected T m_FSM = null;
public void SetFSM(T _FSM)
{
m_FSM = _FSM;
}
[...]
}
Principal Daughter FSM class :
public class PlayerFSM : FSM<PlayerFSM> {
[...]
}
Exemples daughters States class :
public class PlayerMotherState: State<PlayerFSM> {
[...]
}
public class PlayerHighSpeed: PlayerMotherState {
[...]
}
public class PlayerLowSpeed: PlayerMotherState {
[...]
}
Other daughter PlayerMotherState ...
What I want to do it’s a array/list of “type of class” for call ChangeState<> with an id
False exemple :
List<PlayerMotherState> MyList = new List<PlayerMotherState>();
ChangeState<MyList[Id]>();
How do that ? (Assignment of “class types” and use)
I hope that you understand my problem (and my english ^^')
You have a logic error in your example. Like Nerevar kind of pointed out, your List contains instances of type PlayerMotherState. You can’t use an instance reference to create a new version of that class. You need a type. However C# / .NET doesn’t have something like a “type-reference”. What does exist is the System.Type class which is part of the reflection system.
Real “types” can only be staticly used. You can never use the generic syntax with any kind of “variable” (which the exception of generic parameters which aren’t variables but type placeholder).
In short: What you try to do it’s possible with generics. What you can do is using the same method Unity uses for components: reflection. So you could do something like this:
public void ChangeState(System.Type aNewStateType)
{
if (!typeof(State<T>).IsAssignableFrom(aNewStateType))
throw new System.ArgumentException("Only states of type " + typeof(T).Name +" are allowed");
if(m_CurrentState != null)
{
m_CurrentState.End();
}
m_CurrentState = System.Activator.CreateInstance(aNewStateType) as State<T>;
m_CurrentState.SetFSM( this as T );
m_CurrentState.Start();
}
Here you would pass a System.Type object of your desired state as (real / runtime) parameter which will be created with reflection. You can implement this method aside:
public void ChangeState<NewState>() where NewState : State<T>
{
ChangeState(typeof(NewState));
}
which allows you to still use the generic syntax if you need to.
ps: To use a List like you’ve mentioned above you have to use:
List<System.Type> types = new List<System.Type>();
Like Nerevar explained. Now you can pass the System.Type as parameter like this:
ChangeState(types[0]);
or if you know the type at compile time you can use the generic syntax:
Can I suggest you simplify this? It seems to me you are defining different classes for each state and trying to talk the state machine into taking all of them as potential states. All your state classes derive from State.
Rather then trying to do that with complex generics, why don’t you just make State an interface that all state classes inherit and make your FSM work with State?