The problem:
class StatesChain : IState, IHasStateList {
private TasksChain tasks = new TasksChain();
...
public IList<IState> States {
get { return _taskChain.Tasks; }
}
IList<ITask> IHasTasksCollection.Tasks {
get { return _taskChain.Tasks; } <-- ERROR! You can't do this in C#!
I want to return an IList<ITask> from
an IList<IStates>.
}
}
Assuming the IList
returned will be read-only, I know that what I'm trying to achieve is safe (or is it not?). Is there any way I can accomplish what I'm trying? I wouldn't want to try to implement myself the TasksChain
algorithm (again!), as it would be error prone and would lead to code duplication. Maybe I could just define an abstract Chain and then implement both TasksChain
and StatesChain
from there? Or maybe implementing a Chain<T>
class?
How would you approach this situation?
The Details:
I have defined an ITask
interface:
public interface ITask {
bool Run();
ITask FailureTask { get; }
}
and a IState
interface that inherits from ITask
:
public interface IState : ITask {
IState FailureState { get; }
}
I have also defined an IHasTasksList
interface:
interface IHasTasksList {
List<Tasks> Tasks { get; }
}
and an IHasStatesList
:
interface IHasTasksList {
List<Tasks> States { get; }
}
Now, I have defined a TasksChain
, that is a class that has some code logic that will manipulate a chain of tasks (beware that TasksChain
is itself a kind of ITask
!):
class TasksChain : ITask, IHasTasksList {
IList<ITask> tasks = new List<ITask>();
...
public List<ITask> Tasks { get { return _tasks; } }
...
}
I am implementing a State
the following way:
public class State : IState {
private readonly TaskChain _taskChain = new TaskChain();
public State(Precondition precondition, Execution execution) {
_taskChain.Tasks.Add(precondition);
_taskChain.Tasks.Add(execution);
}
public bool Run() {
return _taskChain.Run();
}
public IState FailureState {
get { return (IState)_taskChain.Tasks[0].FailureTask; }
}
ITask ITask.FailureTask {
get { return FailureState; }
}
}
which, as you can see, makes use of explicit interface implementations to "hide" FailureTask
and instead show FailureState
property.
The problem comes from the fact that I also want to define a StatesChain
, that inherits both from IState
and IHasStateList
(and that also imples ITask
and IHasTaskList
, implemented as explicit interfaces) and I want it to also hide IHasTaskList
's Tasks
and only show IHasStateList
's States
. (What is contained in "The problem" section should really be after this, but I thought puting it first would be way more reader friendly).
(pff..long text) Thanks!
On the line where you get an error, you're trying to return IList<IStates>
as if it was an instance of type IList<ITask>
. This doesn't work automtaically, because the two types are different (no matter that the generic parameters are related).
In C# 3.0 or older, there is no way to achieve that automatically. C# 4.0 adds support for covariance and contravariance, which serves exactly this purpose. But as you noted, this works only when the returned collection is read-only. The IList<T>
type doesn't guarantee that, so it isn't annotated as covariant in .NET 4.0.
To make this work using C# 4.0, you'll need to use truly read-only type, which has covariant annotation in the framework - the best option in your case is IEnumerable<T>
(although you could define your own using the out T
modifier).
To add more details, in C# 4.0, you can declare an interface as either covariant or contra-variant. The first case means that the compiler will allow you to perform the conversion you needed in your example (the other case is useful for write-only classes). This is done by adding explicit annotations to the interface declaration (these are already available for .NET 4.0 types). For example, the declaration of IEnumerable<T>
has the out
annotation meaning that it supports covariance:
public interface IEnumerable<out T> : IEnumerable { /* ... */ }
Now, the compiler will allow you to write:
IEnumerable<IState> states = ...
IEnumerable<ITask> tasks = states;