Jason
Jason

Reputation: 87

C# foreach loop thru collection of unknown type

I have a generic method that can be called with 2 different object types, TypeA or TypeB. TypeA and TypeB are essentially identical classes except in name only. I am trying to determine how to prevent from having to duplicate the Foreach loop code for each object type. Is this possible ? thanks.

public class TypeA
{
    public string Name { get; set; }
    public string Department { get; set; }
    public string Total { get; set; }
}

public class TypeB
{
    public string Name { get; set; }
    public string Department { get; set; }
    public string Total { get; set; }
}


 private CsvExport GenerateExport<T>(IEnumerable<T> scores)
 {
    CsvExport export = new CsvExport();

    List<TypeA> aList = null;
    List<TypeB> bList = null;

    Type type = scores.GetType();

    if (type.FullName.Contains("TypeA"))
    {
        aList = scores as List<ObjectaModel>;
    }
    else if (type.FullName.Contains("TypeB"))
    {
        bList = scores as List<ObjectbModel>;
    }

    foreach (var dt in aList)
    {
        export.AddRow();
        export["Name"] = dt.Name;
        export["Department"] = dt.Department;
        export["Total "] = dt.Total;
     };

    return export;
}

Upvotes: 0

Views: 896

Answers (1)

NeilMacMullen
NeilMacMullen

Reputation: 3467

In this particular case I strongly suggest you delegate the hard work to the CsvHelper library which you can also obtain from Nuget and is used like this...

 public void ExportToCsv<T>(string filename, ImmutableArray<T> objects)
 {
    using (var writer = File.CreateText(filename))
    {
        var csv = new CsvWriter(writer);
        csv.WriteRecords(objects);
    }
  }

The more general answer to your question is that you must either have both classes inherit from a common class or interface or you would have to use reflection to look for an obtain the values of the named properties.

Using a common interface...

public interface IScore
{
  int HiScore {get;}
}

public class ScrabbleScore : IScore
{
  public int HiScore {get;set;}
}


public class PacManScore : IScore
{
   public int HiScore {get;set;}
}

public void Export<T>(IEnumerable<T> scores) where T: IScore
{
  foreach(var s in scores)
  {
     CvsExport["Hi score"]= s.HiScore;
  }
}

Using reflection...

        var CsvExport = new Dictionary<string,string>();
        foreach(var o in scores)
        {   
            //note that checking the type for each object enables you to have heterogenous lists if you want
            var objectType= o.GetType();
            foreach(var p in objectType.GetProperties())
            {
               var propertyName = p.Name;
               CsvExport[propertyName] = p.GetValue(o).ToString();
            }
        }

I would treat the reflection solution as the least favoured of the three.

Upvotes: 2

Related Questions