I want to build up a data model, that mainly consists of a graph to be traversed later. Special requirement: a node inside the graph could either be an action to be executed or a container with another graph of actions or containers. During traversal, it has to be checked, if the current node is a container and if so, a traversal of the subgraph shall be started.
How could this be achieved? How should a data model look like, to build up a structure like in the picture below?
So far I got some classes. there are several action types, thus I am using an interface here
public interface IAction : IContainer
{
public ActionType ActionType{ get; set; }
public Name { get; set; }
}
the container contains just a name and a self-reference. I tried to accomplish this initially by using an interface as well, but then I can later only access the interface properties, not the container properties
public interface IContainer
{
public string Name { get; set; }
}
public class Container : IContainer
{
public string Name { get; set; }
public IContainer Content { get; set; }
}
in main the test usage looks like this:
myJob.Content = new QuikGraph.BidirectionalGraph<IContainer, QuikGraph.Edge<IContainer>>();
myJob.Content.AddVertex(new MyCustomAction()
{
ActionType = ActionType.MyCustomAction,
Name = "Test"
});
myJob.Content.Vertices.First().Name // only property I could access, no action-specific ones
What am I doing wrong?
I believe you are missing an operation (a method) in IContainer
that would be callable from any node in your graph and which would behave as you expect (a container forwarding the call to all its enclosed actions and an action doing the real operation).
Also, instead of holding a single reference to an IContainer
in Container
you better have a collection of children IContainer
, since in your diagram a container has 3 actions.
See the Composite pattern for more explanation.
public interface IContainer
{
string Name { get; set; }
void DoWork();
}
public sealed class Action1 : IAction
{
public override DoWork()
{
//Do the real work
}
}
public sealed class Container : IContainer
{
private readonly IReadOnlyList<IContainer> _children;
public Container(IEnumerable<IContainer> children) => _children = children.ToList();
public override DoWork()
{
foreach(var child in _children)
{
child.DoWork();
}
}
}