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

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

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

您可以在.NET 4.0中使用dynamic关键字 ,因为您正在处理内置类型。 否则,你会使用多态。

例:

 using System; using System.Collections.Generic; class Test { static void Main() { List stuff = new List { 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 

这取决于设计的重要性:

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

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

这是一个带注释的工作示例。 它使用通用的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> MyToStringLookup = new Dictionary>() { {typeof(String), new Func( obj => obj.ToString() )}, {typeof(DateTime), new Func( obj => ((DateTime)obj).ToString("d") )}, {typeof(MyPerson), new Func( obj => (obj as MyPerson).LN )}, }; // your list of objects List MyObjects = new List() { "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()); } } } 

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

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

希望这可以帮助! ;)

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

编辑阿巴斯评论:

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

例如,如果我写这个:

 ///  /// Displays ":)" if obj is a Foo ///  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); } 

将显示“:(”。

如果你写,它会工作

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

这是switch的概念 ,与非互斥的值不兼容。 这就是为什么当值不是独占时打开Flags枚举时可能会出现编译错误的原因。