So I\'m just hacking around with a state machine type I was working on and mostly wanting to just try out the Activator.CreateInstance method to see what it was like, and I
This issue happens because:
ITransitionContainer
is not a covariant interface over its type arguments. AddTransition
method generic arguments are not constrained to be reference types._transitions
is not a dictionary with ITransitionContainer
values, so without changing it to Dictionary>
we still won't be able to add even properly resticted covariant transtions.Consider the following simplified case:
public interface ITransition
{
}
public class SomeTransition : ITransition
{
}
public interface ITest
where TTransition : ITransition
{
TTransition Value { get; }
}
public class SomeTest : ITest
where TTransition : ITransition
{
public TTransition Value
{
get
{
throw new NotImplementedException();
}
}
}
It will fail in both
public static void Do()
where TTransition : ITransition
{
ITest item = new SomeTest();
}
and
ITest item = new SomeTest();
If you make ITest
covariant
public interface ITest
, then it will fail only in generic method. Because here TTransition
can be a struct and co/(contra)variance doesn't work with value types:
public static void Do()
where TTransition : ITransition
{
ITest item = new SomeTest();
}
But if you make that method constrained to only reference types, then it will work in both cases:
public static void Do()
where TTransition : class, ITransition
{
ITest item = new SomeTest();
}
Apply the same principle(out
and class
) to your two generic arguments and it will do the job.
public interface IState
{ }
public interface ITransition
{ }
// !!!!! - Here we add out specifier
public interface ITransitionContainer
where TTransition : ITransition
where TStateTo : IState
{
Type StateTo
{
get;
}
TTransition Transition
{
get;
}
}
public interface IStateContainer where T : IState
{
T State
{
get;
}
}
public class TransitionContainer : ITransitionContainer
where TTransition : ITransition
where TStateTo : IState
{
public TransitionContainer()
{
StateTo = typeof(TStateTo);
Transition = Activator.CreateInstance();
}
public Type StateTo { get; private set; }
public TTransition Transition { get; private set; }
}
public class StateContainer : IStateContainer where T : IState
{
private Dictionary> _transitions =
new Dictionary>();
public StateContainer()
{
State = Activator.CreateInstance();
}
public T State { get; private set; }
public int TransitionCount
{
get { return _transitions.Count; }
}
public void AddTransition()
// !!!!!! - Here we add class constraints
where TTransition : class, ITransition, new()
where TStateTo : class, IState, new()
{
var transitionContainer = new TransitionContainer();
_transitions.Add(typeof(TTransition), transitionContainer);
}
}