C#在运行时切换对象类型

时间:2011-08-22 15:28:06

标签: c# .net

我有List<object>。我想循环遍历列表并以比o.ToString()更友好的方式打印出值,以防某些对象是布尔值或日期时间等。

如何构建一个我可以调用MyToString(o)的函数并返回一个正确格式化的字符串(由我指定)作为其实际类型?

6 个答案:

答案 0 :(得分:6)

您可以在.NET 4.0中使用dynamic keyword,因为您正在处理内置类型。否则,您将使用多态性。

示例:

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");
    }
}

打印出来:

I'm a date
I'm a bool
I'm an int

答案 1 :(得分:1)

取决于设计的重要性:

  • if o.GetType()/ o.GetType()上的语句或switch语句。名称
  • 实现一种IShow-Interface(使用方法void Show(对象o)并使用Dictionary将类型映射到此接口的实现并仅使用
    if (TryGetValue(o.GetType, out show)) show.Show(o); 
  • 坚持下去并让对象告诉故事(覆盖ToString)...是的你不想要这个但恕我直言这是最好的方法

答案 2 :(得分:1)

您是否考虑以更友好的方式覆盖ToString()?

答案 3 :(得分:1)

这是一个带注释的工作示例。它使用通用的Type of Dictionary和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());
        }
    }
}

答案 4 :(得分:0)

您唯一的选择是if-else-if结构。 switch不允许打开类型,因为switch结构需要一个具有互斥值的可枚举集合(并且一个对象可以有几种类型)。

编辑阿巴斯评论:

GetType()。名称有效但会导致您在此上下文中出现潜在错误,因为它可能会返回您不知道的类型。即使一个对象存储为类型A,GetType()。如果B继承A,Name也可能返回“B”。如果你在执行切换的方法的上下文中不知道B(它可能是一个类型来自另一个继承了当前库之一的库,它可能是在你编写方法后添加的类型),你会在伪类型切换中错过它。如果你写if(obj is A),你就不会。

例如,如果我这样写:

/// <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;
    }
}

评论是谎言,因为

public class Bar : Foo
{
}

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

将显示“:(”。

如果你写

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

交换机的概念与非互斥值不兼容。这就是为什么当值不是独占的时,当你打开Flags枚举时,你可以得到编译错误

答案 5 :(得分:0)

这样的事可能会让你在路上:

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;
}

希望这有帮助! ;)