【问题标题】:C#: Parse different classes as object and display property values the same wayC#:将不同的类解析为对象并以相同的方式显示属性值
【发布时间】:2015-12-09 10:31:47
【问题描述】:

我在 C# 控制台应用程序中有几个类。

public class Cars:List<Car>
{}

和:

public class Drivers:List<Driver>
{}

目标是始终以相同的方式呈现控制台输出,无论 carsdrivers 是否被解析为呈现方法。所以参数的类型是object。当然,属性可能有不同的名称。

输出应该是这样的:

// Cars
Brand HP  Topspeed
VW    100 200
VW    90  150

// Drivers
Name Age Sex 
Pit  18  m
Jane 20  f

所以我需要读取属性名称以使其成为列标题,然后读取每个对象的值。我已经搜索了一段时间,总是出现这样的事情:

public static void RenderOutput(object obj)
{
    foreach (var prop in obj.GetType().GetProperties())
    {
    }
}

虽然在运行时将鼠标悬停在 obj 上显示所有所需的对象和属性(品牌、HP、VW、100、...)非常好,但我无法从 prop 项目 car 中挤出值cardriver driver

有什么建议吗? 谢谢 jimbo2015

【问题讨论】:

    标签: c# parsing reflection gettype getproperties


    【解决方案1】:

    正确的方法是实现一个接口(正如@Adarsha 所说)并在每个类中实现 RenderOutput() 方法,以使其具有自己的特定实现,并具有正确的属性列表、正确的格式等。

    现在,如果您仍想坚持自己的方法,这将奏效。

    假设这些是你的类

    public class Car
    {
        public string Brand { get; set; }
        public int HorsePower { get; set; }
        public int TopSpeed { get; set; }
    }
    
    public class Driver
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Sex { get; set; }
    }
    

    现在,这些方法将使用反射来读取属性并将它们写入控制台。

    public static void RenderOutput(IEnumerable<object> collection)
    {
        RenderHeader(collection.First()); //collection not validated
        collection.ToList().ForEach(item => RenderBody(item));
    }
    
    private static void RenderHeader(object obj)
    {
        var properties = obj.GetType().GetProperties().OrderBy(p => p.Name);
        Console.WriteLine("");
        foreach (var prop in properties)
        {
            Console.Write(prop.Name + "\t"); //or ("{0,15}", prop.Name)
        }
    }
    
    private static void RenderBody(object obj)
    {
        var properties = obj.GetType().GetProperties().OrderBy(p => p.Name);
        Console.WriteLine("");
        foreach (var prop in properties)
        {
            Console.Write((prop.GetValue(obj, null)) + "\t"); //or ("{0,15}", (prop.GetValue(obj, null)))
        }
    }
    

    您现在可以在任何IEnumerable&lt;T&gt; 上调用RenderOutput() 方法来获得所需的输出。可以这样测试

    static void Main(string[] args)
    {
        //test data
        var cars = new List<Car>();
        cars.Add(new Car { Brand = "BMW", HorsePower = 100, TopSpeed = 200 });
        cars.Add(new Car { Brand = "VW", HorsePower = 90, TopSpeed = 150 });
        var drivers = new List<Driver>();
        drivers.Add(new Driver { Name = "Prit", Age = 18, Sex = "Male" });
        drivers.Add(new Driver { Name = "Jane", Age = 20, Sex = "Female" });
    
        RenderOutput(cars);
        Console.WriteLine();
        RenderOutput(drivers);
    
        Console.ReadLine();
    }
    

    这是生成的输出:

    Brand   HorsePower      TopSpeed
    BMW     100     200
    VW      90      150
    
    Age     Name    Sex
    18      Prit    Male
    20      Jane    Female
    

    注意:这不适用于复杂类型的属性!

    【讨论】:

      【解决方案2】:

      您应该在使用反射时使用BindingFlags 以获取实例的属性。例如,要获取 object o 的所有 private 属性,您应该使用:

      IEnumerable<PropertyInfo> props = o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic);
      foreach (PropertyInfo info in props)
      {
          Console.WriteLine(info.Name + info.GetValue(o));
      }
      

      话虽如此,请注意拥有一个interface 将由CarDriver 实现打印方法在设计上可能更正确。如果您仍然想使用反射,我建议您在要打印的属性上添加Attributes,并使用所需的显示名称,以便将显示与代码的命名约定分开。

      【讨论】:

        【解决方案3】:

        我建议去interface 路由,有一个接口将有方法RenderOutput。汽车和司机都将实现该接口,并提供他们自己的方法实现。这将更合适,因为汽车方法不知道驱动程序或签证。在调用方法的地方,不是传递对象,而是调用实例方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-03-04
          • 2018-11-03
          • 1970-01-01
          • 2021-03-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-05
          相关资源
          最近更新 更多