Idanis
Idanis

Reputation: 1988

Avoiding multiple "if" statements when iterating a list of objects c#

I have various classes which generate excel graphs.

Each class generates a different graph.

They all share the same private variables, with different values.

I wish to write a generic code, in order to prevent "if" statements to determine which graph is it.

Here is an example of one of the classes:

using System;

namespace GraphsGenerator
{
   public class GraphOne
   {
       #region Private Members

       private string m_baseDir = "";
       private static string m_graphName = "GraphOne";
       private string m_imageFile = m_graphName + Utils.ImageExtension;

       #endregion Private Members

       #region Properties

       public string BaseDir
       {
           set { m_baseDir = value; }
       }
       public string GraphName
       {
           get { return m_graphName; }
       }
       public string ImageFile
       {
           get { return m_imageFile; }
           set { m_imageFile = value; }
       }

       #endregion Properties

       #region Constructor


       public HandTrackingGraphs(string baseDir)
       {
           m_baseDir = baseDir;
       }

       #endregion Constructor
   }
 }

I tried to do this in my main:

List<object> listOfGraphs = new List<object>();
listOfGraphs.Add(new GraphOne());
listOfGraphs.Add(new GraphTwo());
listOfGraphs.Add(new GraphThree());

foreach (object currentGraph in listOfGraphs)
{
   string imageFile = currentGraph.ImageFile;
}

But of course this cannot be done.

Any ideas?

Upvotes: 2

Views: 308

Answers (5)

Hossain Muctadir
Hossain Muctadir

Reputation: 3626

In this case all you need is to implement Strategy Pattern To get some idea see this code

abstract class AbsGraph
{
    public string ImageFile { get; protected set; }
    //other properties

    public abstract void DrawGraph();
    //other methods

    public void CommonMethod()
    { }
    //other common method
}

class Graph1 : AbsGraph
{
    public override void DrawGraph()
    {
        //do graph specific task
    }
}

class Graph2 : AbsGraph
{
    public override void DrawGraph()
    {
        //do graph specific task
    }
}

class Graph3 : AbsGraph
{
    public override void DrawGraph()
    {
        //do graph specific task
    }
}

Now you can do

var absGraphs = new List<AbsGraph>
                    {
                        new Graph1(),
                        new Graph2(),
                        new Graph3()
                    };
foreach (var graph in absGraphs)
{
    graph.DrawGraph();
}

Upvotes: 0

James
James

Reputation: 82136

Interfaces have already been suggested, so to give you another alternative - you could use a base class because you not only share common properties/methods but you also share common implementation e.g.

public abstract class Graph
{
   #region Private Members

   private string m_baseDir = "";
   private string m_imageFile = m_graphName + Utils.ImageExtension;

   #endregion Private Members

   #region Properties

   public string BaseDir
   {
       set { m_baseDir = value; }
   }
   public string GraphName
   {
       get { return m_graphName; }
   }

   public abstract string ImageFile { get; }

   #endregion Properties

   #region Constructor


   public HandTrackingGraphs(string baseDir)
   {
       m_baseDir = baseDir;
   }

   #endregion Constructor
}

public class GraphOne : Graph
{
    public override string ImageFile { get { return "GraphOne"; } }
}

public class GraphTwo : Graph
{
    public override string ImageFile { get { return "GraphTwo"; } }
}

public class GraphThree : Graph
{
    public override string ImageFile { get { return "GraphThree"; } }
}

Then your usage becomes

List<Graph> listOfGraphs = new List<Graph>();
listOfGraphs.Add(new GraphOne());
listOfGraphs.Add(new GraphTwo());
listOfGraphs.Add(new GraphThree());

foreach (IGraph currentGraph in listOfGraphs)
{
    string imageFile = currentGraph.ImageFile;
}

Upvotes: 1

CodeCaster
CodeCaster

Reputation: 151720

But of course this cannot be done.

It can, using interfaces. Define an interface containing the method you want to run:

public interface IGraphWithImageFile
{
    string ImageFile { get; }
}

Then apply the interface to all classes, and declare the list as List<IGraphWithImageFile>.

Upvotes: 4

Justin Harvey
Justin Harvey

Reputation: 14682

Make all the classes inherit from a common GraphBase abstract class. Put your common properties as abstract on this class, then override them in the derived classes.

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1503519

They all share the same private variables, with different values.

They should all implement the same interface, which exposes the ImageFile property. For example:

public interface IGraph
{
    // TODO: Consider making this read-only in the interface...
    public string ImageFile { get; set; }
}

Then you can have:

List<IGraph> listOfGraphs = new List<IGraph>();
listOfGraphs.Add(new GraphOne());
listOfGraphs.Add(new GraphTwo());
listOfGraphs.Add(new GraphThree());

foreach (IGraph currentGraph in listOfGraphs)
{
   string imageFile = currentGraph.ImageFile;
}

You could use an abstract base class instead of an interface, too. That's a bit more restrictive, but it means graphs could share common implementation too.

(You could even create an interface implemented by an abstract base class, if you really wanted the flexibility but also code reuse.)

Upvotes: 8

Related Questions