C# Switch on Object Type at Runtime

前端 未结 6 1157
悲&欢浪女
悲&欢浪女 2020-12-07 03:17

I have a List. 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
相关标签:
6条回答
  • 2020-12-07 03:43

    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
    0 讨论(0)
  • 2020-12-07 03:44

    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! ;)

    0 讨论(0)
  • 2020-12-07 03:45

    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.

    0 讨论(0)
  • 2020-12-07 03:55

    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());
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-07 03:56

    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
    
    0 讨论(0)
  • 2020-12-07 03:59

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

    0 讨论(0)
提交回复
热议问题