0

I am attempting to implement some more complex data structures in c# working with no libraries other than System. Currently i am working on graphs.

I have created 3 classes already to represent nodes, directed edges, and undirected edges. Each of these can have a different data type e.g. node<string> will be a node with information stored as a string and directedEdge<string> will link nodes that store strings.

My graph class is declared as Graph<dataType, edgeType> (for now I am assuming all edges in a single graph are the same type), and I would like to branch within this class based on whether a directed or undirected edge is being used. The code bellow does not work, but explains the functionality I would like to achieve.

if (edgeType == directedEdge<dataType>)
{

}
else if (edgeType == undirectedEdge<dataType>)
{

}
else
{

}

Is there any way to implement something like what is shown above? If so, how?

LHOS
  • 1
  • 1
  • 1
    Please provide more code context. From your example, it is unclear why it does not work/fit your requirements. – dymanoid Feb 28 '20 at 12:38
  • 1
    I'm not sure about what you're asking, but you may be looking for something like `if (YourEdgeObject is directedEdge)` – Cid Feb 28 '20 at 12:41
  • FYI - look at [this tree structure](https://stackoverflow.com/a/25166761/380384) which combines data, nodes and edges into one class. – John Alexiou Feb 28 '20 at 13:57

2 Answers2

4

Well you could use pattern matching:

switch (edge)
{
    case directedEdge<dataType> de:
        // Do whatever..
        break;
    case undirectedEdge<dataType> ue:
        // Do whatever..
        break;
    default:
        // Do whatever..
        break;
}

In the above example edge is an actual instance, not a type.

But this might not be the best design to implement, because as you introduce new edge types, you will need to update the switch statement also.

If you do this in multiple places, the effects are amplified.

A better way, following OOP principles, would be to define the behaviour in the edge types themselves:

abstract class Edge
{
    abstract void DoSomething();
}

class directedEdge<T> : Edge
{
    override void DoSomething() { }
}

class undirectedEdge<T> : Edge
{
    override void DoSomething() { }
}

then in your method, its simply:

Edge edge = // Some specific edge type
edge.DoSomething();
Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35
0

There are several ways to do this, following the evolution of C# over the years.

  • Check runtime type

        Edge<int> edge = GetEdge(1);
        if (edge.GetType() == typeof(DirectedEdge<int>))
        {
        }
        else if(edge.GetType() == typeof(UnidirectedEdge<int>))
        {
        }
    
  • Use casting with the as keyword

        Edge<int> edge = GetEdge(1);
        DirectedEdge<int> directed_edge = edge as DirectedEdge<int>;
        if (directed_edge != null)
        {
            // Use directed_edge
        } else {
            UnidirectedEdge<int> uni_edge = edge as UnidirectedEdge<int>;
            if (uni_edge != null)
            {
                // Use uni_edge
            }
        }
    
  • Use pattern matching if statements

        Edge<int> edge = GetEdge(1);
    
        if (edge is DirectedEdge<int> directed_edge)
        {
            // Use directed_edge
        }
        else if (edge is UnidirectedEdge<int> uni_edge)
        {
            // Use uni_edge
        }
    
  • Use pattern matching switch statement

        Edge<int> edge = GetEdge(1);
        switch (edge)
        {
            case DirectedEdge<int> directed_edge:
                // Use directed_edge
            case UnidirectedEdge<int> uni_edge:
                // Use unit_edge
            default:
                throw new NotSupportedException();
        }
    
John Alexiou
  • 28,472
  • 11
  • 77
  • 133