4

I have a List<object>. I want to loop over the list and print the values out in a more friendly manner than just o.ToString() in case some of the objects are booleans, or datetimes, etc.

How would you structure a function that I can call like MyToString(o) and return a string formatted correctly (specified by me) for its actual type?

Davis Dimitriov
  • 4,159
  • 3
  • 31
  • 45

6 Answers6

6

You can use the dynamic keyword for this with .NET 4.0, since you're dealing with built in types. Otherwise, you'd use polymorphism for this.

Example:

using System;
using System.Collections.Generic;

class Test
{
    static void Main()
    {
        List<object> stuff = new List<object> { DateTime.Now, true, 666 };
        foreach (object o in stuff)
        {
            dynamic d = o;
            Print(d);
        }
    }

    private static void Print(DateTime d)
    {
        Console.WriteLine("I'm a date"); //replace with your actual implementation
    }

    private static void Print(bool b)
    {
        Console.WriteLine("I'm a bool");
    }

    private static void Print(int i)
    {
        Console.WriteLine("I'm an int");
    }
}

Prints out:

I'm a date
I'm a bool
I'm an int
wsanville
  • 37,158
  • 8
  • 76
  • 101
1

that depends on how important the design will be:

  • if statements or switch-statement on o.GetType()/o.GetType().Name
  • implementing a kind of IShow-Interface (with a method void Show(object o) and using a Dictionary to map types to implementations of this interface and just using
    if (TryGetValue(o.GetType, out show)) show.Show(o); 
  • just stick to it and let the objects tell the tale (override ToString) ... yes you don't want this but IMHO this is the best way to do this
Random Dev
  • 51,810
  • 9
  • 92
  • 119
1

Did you consider overriding ToString() in a more friendly way?

Vinzz
  • 3,968
  • 6
  • 36
  • 51
  • So, he's going to create MyBooleans, MyIntegers, MyDates, etc? if they were his own classes then this would be totally applicable, and although this would work, it just seems a bit painful to subclass a bunch of builtin types just to provide .ToString() overrides. Reasonable answer, but personally I don't think I could do that and be happy with it. – deepee1 Aug 22 '11 at 15:44
1

Here's a working example with comments. It uses a generic Dictionary of Type and Lambda Func.

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        // a custom class
        public class MyPerson
        {
            public string FN { get; set; }
            public string LN { get; set; }
        }
        static void Main(string[] args)
        {
            // your prebuilt dictionary of Types to Lambda expressions to get a string
            Dictionary<Type, Func<object, String>> MyToStringLookup = new Dictionary<Type, Func<object, string>>()
            {

                {typeof(String), new Func<Object, String>( obj => obj.ToString() )},
                {typeof(DateTime), new Func<Object, String>( obj => ((DateTime)obj).ToString("d") )},
                {typeof(MyPerson), new Func<Object, String>( obj => (obj as MyPerson).LN )},
            };
            // your list of objects
            List<Object> MyObjects = new List<Object>()
            {
                "abc123",
                DateTime.Now,
                new MyPerson(){ FN = "Bob", LN = "Smith"}
            };
            // how you traverse the list of objects and run the custom ToString
            foreach (var obj in MyObjects)
                if (MyToStringLookup.ContainsKey(obj.GetType()))
                    System.Console.WriteLine(MyToStringLookup[obj.GetType()](obj));
                else // default if the object doesnt exist in your dictionary
                    System.Console.WriteLine(obj.ToString());
        }
    }
}
Louis Ricci
  • 20,804
  • 5
  • 48
  • 62
0

Your only option is an equivalent to if-else-if structure. switch does not allow switch on type, because the switch structure needs an enumerable ensemble with mutually exclusive values (and an object can be of several types).

Edit for Abbas comment:

GetType().Name is valid but will lead you to potential errors in this context, because it can return a type you don't know. Even if an object is stored as a type A, GetType().Name can potentially return "B" if B inherits A. If you don't know B in the context of the method doing the switch (it could be a type from another library that inherits one of the current library, it could be a type that has been added after you wrote your method), you will miss it in your pseudo-typeswitch. If you write if(obj is A) though, you won't.

Example, if I write this:

/// <summary>
/// Displays ":)" if obj is a Foo
/// </summary>
public static void CaseType(object obj)
{
    switch(obj.GetType().Name)
    {
        case "Foo":
           MessageBox.Show(":)");
           break;
             default:
           MessageBox.Show(":(");
           break;
    }
}

The comment is a lie, because

public class Bar : Foo
{
}

public static void CaseTypeSpecialized()
{
     Foo obj = new Bar();
     CaseType(obj);
}

will display ":(".

It will work if you write

/// <summary>
/// Displays ":)" if obj is a Foo
/// </summary>
public static void CaseType(object obj)
{
    if (obj is "Foo")
    {
        MessageBox.Show(":)");
    }
    else
    {
        MessageBox.Show(":(");
    }
}

It's the concept of switch that is incompatible with non-mutually exclusive values. That's why you can get compilation errors when you switch on a Flags enum when the values are not exclusives.

Evren Kuzucuoglu
  • 3,781
  • 28
  • 51
0

Somthing like this might get you on the way:

private static String MyToString(object o)
{
    var val = "";
    switch (o.GetType().Name)
    {
        case "Boolean": val = ((bool)o) ? "this is true" : "this is false"; break;
        case "DateTime": val = "The date is: " + ((DateTime)o); break;
        case "Int32": val = "The number-value is: " + (int)o; break;
    }
    return val;
}

Hope this helps! ;)

Abbas
  • 14,186
  • 6
  • 41
  • 72