Search code examples
c#foreachiteratoroverloading

Smarter way to overload methods?


I have a class called Block that has a Draw method. I want to make a function that draws a group of blocks all at once. Since some groups are Arrays and some are lists, I had to add an overload that basically does the same thing as the base function but just takes in a different type of parameter. Any ideas on how to improve this code?

public static void DrawAll(Block[] arr) {
    foreach(Block b in arr)
        b.Draw();
}

public static void DrawAll(List<Block> arr) {
    foreach(Block b in arr)
        b.Draw();
}

I tried looking into Generics but I can't iterate through T because the compiler doesn't know it's a collection of blocks.

// Doesn't work
public static void DrawAll<T>(T arr) {
    foreach(var b in arr)
        b.Draw();
}

Using the is keyword and casting also doesn't work because, from what I understand, you can't make two different casts in the same if statement. So I'll have to separate the casts and that just makes the code look even worse:

// Even dummer than just doing the overload
public static void DrawAll<T>(T arr) {
    if (arr is Block[] blocksA)
        foreach(Block b in blocksA)
            b.Draw();

    else if (arr is List<Block> blocksL) 
        foreach(Block b in blocksL)
            b.Draw();

    else throw new Exception("not a collection of blocks");
}

Solution

  • What you need is a useful common base type of List<T> and T[] or an interface implemented by both of them.

    • If you don't need the index (e.g. because you are using foreach), then IEnumerable<Block> will work for all kinds of collections and also (unrealized) results of LINQ expressions, e.g.: blocks.Where(b => b.Name.StartsWith("A")).

      public static void DrawAll(IEnumerable<Block> blocks) {
           foreach(Block b in blocks)
               b.Draw();
      }
      
    • If you need the index (e.g. because you are using for), then IList<Block> will accept List<Block> as well as Block[].

      // E.g. drawing blocks in reverse order
      public static void DrawAll(IList<Block> blocks) {
           for (int i = blocks.Count - 1; i >= 0; i--)
               blocks[i].Draw();
      }