List all IEnumerables

I need to send various IEnumerables to an object Printer

. This printer object will then do something to them inside the foreach loop.

class Printer
{
    public Printer(IEnumerable list)
    {
        foreach (var enumerable in list)
        {
            //DO STUFF
        }
    }
}

      

This allows me to forward any objects such as List<T>

to a printer object. such as

    var list = new List<string> {"myList"};
    new Printer(list); //mylist

      

This works great. BUT if I post a Dictionary<T, T>

, for example:

var dictionary = new Dictionary<int, string> {{1, "mydict"}};
new Printer(dictionary); //[1, mydict]

      

It will have a key and a value. However, I would like to have separate access to the property Value

inside the loop foreach

. All I have access to is an enumerable object that has no properties that I can use.

Now what if the datatype T is an object containing multiple properties (this applies to both examples). How can I use these properties in my foreach loop?

Should I honestly create a constructor overload, for some possible data type I could send it?

Also, everything I need to do in the foreach is independent of any data types - since it won't manipulate everything. I really need ACCESS for all properties.

Also, this is just sample code, not production code that I am using in my application.

+2


source to share


7 replies


Can you change the code for the Printer class? If he took something like IEnumerable<IPrintable>

instead of simple IEnumerable

, it would be easier. With an interface like this:

interface IPrintable
{
    void Print();
}

      

Then all objects that will be sent Printer

to will have to implement this interface. Then you can do:

class Printer
{
    public Printer(IEnumerable<IPrintable> list)
    {
        foreach (var enumerable in list)
        {
            enumerable.Print();
        }
    }
}

      



And if you have a dictionary for printable objects, something like:

var dict = new Dictionary<int,IPrintable>();

      

You can simply pass the values ​​to the function:

var printer = new Printer(dict.Values);

      

+4


source


You can change your method to accept a delegate that returns the data the print method needs. Something like that:

// You will not need this class, if you always want a single string result.
class PrinterData
{
    public string Value { get; set; }
    // More properties?
}
class Printer
{
    public Printer<T>(IEnumerable<T> list, Func<T, PrinterData> func)
    {
        foreach (T item in list)
        {
            PrinterData data = func(item);
            // Do something with the data.
        }
    }
}

      



Using:

int[] ints = new int[] {1,2,3};
new Printer().Print(ints, x => new PrinterData() { Value = x.ToString() });

var dictionary = new Dictionary<int, string> {{1, "mydict"}};
new Printer().Print(dictionary, x => new PrinterData() { Value = x.Name + " = " + x.Value });

      

Eric Stendhal's answer is very similar.
+4


source


You must retrieve the enum with the values ​​you want to pass before you call new printer (). In the case of a dictionary, it's simple: just use dict.Values. More general case:

var list = List<MyObject>()...

var printer = new Printer(list.Select(x => x.MyProperty));

      

+3


source


If you want to handle different types differently, you should probably do different methods. If you want to treat them the same, you must accept the generic interface and only use the methods defined for the interface.

Could be done

if (list is Dictionary<int, string>) {
    // do special case
}

      

but I shudder at the thought.

You can even check in general terms:

class Printer<T>
{
    public Printer<T>(IEnumerable list)
    {
        foreach (var enumerable in list)
        {
            if (list is Dictionary<T, T>) {
                //DO STUFF
            }
        }
    }
}

      

+2


source


The problem is that a collection, although enumerable, can contain different types of objects, as you saw with the difference between List

and Dictionary

.

To get around this without coding for each object type, you would only need to accept an enumerable collection of a specific type that you define for example IEnumerable<IMyType>

.

+1


source


If you cannot do anything at the called party, make sure that he is transmitting IEnumerable

which is "valid" for the printer, for example, transmit dictionary.Values

instead dictionary

in your example. However, if the class is public and will be used by third party users, you'd be better off adding some general constraint to yours IEnumerable

as pointed out by others.

+1


source


Here's the result: I used your guys, so I guess I shouldn't vote on my own.

class Printer
{
    public Printer(IEnumerable<IPrintable> list) //Accepts any collection with an object that implements IPrintable interface
    {
        foreach (var enumerable in list) //iterate through list of objects
        {
            foreach (var printable in enumerable)//loops through properties in current object
            {
                //DO STUFF 
            }
        }
    }
}

interface IPrintable : IEnumerable { }
class SomeObject : IPrintable
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }

    public interface IEnumerable
    {
        IEnumerator GetEnumerator(); //Returns a Enumerator
    }

    public IEnumerator GetEnumerator()
    {
        yield return Property1;
        yield return Property2;
    }
}

      

I would naturally need to implement my own GetEnumerator () foreach object - no problem!

0


source







All Articles