How to force others to obey a specific layout for a child class?

175 views Asked by At

I have an abstract class as follows:

public abstract class Node
{
    public abstract void run();
}

There are some child nodes that may have several properties as input and output. But all the operation is done just in run() method that each Node should implement. For example a Node that draws a line could be something like this:

public class LineNode : Node
{
    [Input]
    public Point a;
    [Input]
    public Point b;
    [Output]
    public Line line;
    public override void run()
    {
        line = new Line(a, b);
        // draw line ...
    }
}

[AttributeUsage(AttributeTargets.Field)]
public class Input : System.Attribute
{

}
[AttributeUsage(AttributeTargets.Field)]
public class Output : System.Attribute
{

}

As you see I don't have any prior information about fields in the child classes. ** For a Node to be a valid node in convention, It is just required to have at least one output.** I want to force all other users to have at least one output in their Nodes so I can find it by reflection by looking for a field that [Output] attribute is applied to.
Is this possible?
And if this is, Is it the best way?

Thanks for any help


Here the same issue raised but the suggested solution settled it in the run time. I was looking for an Object Oriented solution though. Which one is more logical actually?

3

There are 3 answers

0
eFloh On

How about using an Interface IOutputDefinition and defining an abstract ICollection<IOutputDefinition> in the Node-class. All Implementers have to fill this in order to enable your code to determine which outputs the implementation will produce.

You may define any Metadata-Properties like Name, Output-Type, ... or even a property containing a Getter-Expression for the Output in the Interface

6
George Vovos On

You could do something like this

public interface IRunnable<T>
{
    T Run();
}

And then every class that implements this interface must provide this run method and return a (strongly typed ) result.

Or if the run method does not return the result

public interface IRunnable<T>
{
    void Run();
    T Value {get;}
}
public class LineNode : IRunnable<Line>
{
    [Input]
    public Point a;
    [Input]
    public Point b;

    private Line line;
    public Line Value { get{return line;}}
    public override void run()
    {
    line = new Line(a, b);
    // draw line ...
    }

}

2
Dan Field On

Define something like this in your base class:

public abstract class Node
{
    [Output]
    public abstract object DefaultOuptut;
    public abstract void run();
}

And now your line class might look like this:

public class LineNode : Node
{
    [Input]
    public Point a;
    [Input]
    public Point b;
    [Output]
    public Line line;
    [Output]
    public override object DefaultOutput { get { return line; } }

    public override void run()
    {
        line = new Line(a, b);
        // draw line ...
    }
}

You could use some generic typing as well on the default object:

public abstract class Node<T>
{
   [Output]
   public abstract T DefaultOutput;
   public abstract void run();
}

This would still allow for other outputs that are not Ts.