Search code examples
c#methodspropertiesienumerable

Can I use an IEnumerable with different properties for each entry as a method argument?


I'm relatively new to C#. I'm trying to use an IEnumerable collection as an argument to a C# function, but I want to define the properties that I want to return as well.

Suppose I have a car IEnumerable with properties such as color and brand. Each entry has a color and a brand, of course. I'm trying to split the enumerable information on the function below.

Is something like this possible?

public string stringforeach(IEnumerable coll, <<color>>, <<brand>>)
    {
        string write = "";
        int i = 0;
        foreach (var element in coll)
        {

            write += string.Concat(i.ToString() + ";" + element.color+ ";" + element.bramd + "\n");
            i++;
        }

     

        return write;
    }

Solution

  • Use two separate features of C#:

    Use generics so that the method can accept collections of a specific type with the compiler knowing about the specific type being used for a specific call of the method.

    Use delegates as parameters to be able to pass functions (or lambda expressions) to specify which property of an object to access.

    public string StringForeach<T>(IEnumerable<T> coll, Func<T, string> property1, Func<T, string> property2)
    {
        string write = "";
        int i = 0;
        foreach (var element in coll)
        {
            write += i + ";" + property1(element) + ";" + property2(element) + "\n";
            i++;
        }
    
        return write;
    }
    

    Given the following Car class

    public class Car
    {
        public string Color { get; set; }
        public string Brand { get; set; }
    }
    

    you can call the method like this:

    List<Car> cars = new List<Car>();
    cars.Add(new Car { Color = "Red", Brand = "BMW" });
    cars.Add(new Car { Color = "Black", Brand = "Mercedes" });
    
    string text = StringForeach<Car>(cars, c => c.Color, c => c.Brand);
    

    Some explanations:

    public string StringForeach<T>(IEnumerable<T> coll, Func<T, string> property1, Func<T, string> property2)
    

    This declares a generic method which can be called with a specific type T. It accepts three parameters:

    • IEnumerable<T> coll: A collection of objects of type T
    • Func<T, string> property1: A delegate to a function that accepts an argument of type T and returns a string
    • Func<T, string> property2: See above.

    When calling the method

    string text = StringForeach<Car>(cars, c => c.Color, c => c.Brand);
    

    we specify that we call the method with type T being the concrete type Car.

    The lambda expression

    c => c.Color
    

    is a short form of writing a function delegate for this function:

    string SomeFunc(Car c) 
    {
      return c.Color;
    }
    

    The Bars object from the API implements IEnumerable. In order to convert this into the type IEnumerable<Bar>, you can use this syntax:

    IEnumerable bars = MarketData.GetBars();
    IEnumerable<Bar> typedBars = bars.Cast<Bar>();
    

    You can then call the method like this:

    string text = StringForeach<Bar>(typedBars, c => c.OpenTime, c => c.Low);
    

    Because the properties you want to use are not of type string directly, change the syntax like this:

    public string StringForeach<T>(IEnumerable<T> coll, Func<T, object> property1, Func<T, object> property2)
    {
        string write = "";
        int i = 0;
        foreach (var element in coll)
        {
            write += i + ";" + property1(element) + ";" + property2(element) + "\n";
            i++;
        }
    
        return write;
    }
    

    String conversion happens automatically.