使用反射显示来自不同自定义类的数据

时间:2019-01-09 12:41:05

标签: c# serialization reflection

我想创建一个显示对象中包含的信息的方法,该方法将与任何对象一起动态工作。我在处理其他自定义类的属性时遇到麻烦。在下面的示例中,Person具有PhonesOccupations两者都是其他类。显示数据时,当前屏幕上的值为:

TestReflection.Person
Name: Mary
Phones: TestReflection.Phones
Occupations: TestReflection.Occupations

它仅显示类名,例如TestReflection.Phones,而不显示该对象内部的数据。

如何更改此代码以显示类似的信息?

TestReflection.Person
Name: Mary
Phones:
    TestReflection.Phones
    Type: 1
    Number: 555XYZ
Occupations: 
    TestReflection.Occupations
    Type: 5
    Description: Secretary

这是我的代码:

class Program
{
    static void Main(string[] args)
    {
        List<Person> listPeson = new List<Person>();
        var person1 = new Person();
        person1.Name = "Mary";
        person1.Phones = new  Phones { new Phone { Type = 1, Number = "555XYZ" } };
        person1.Occupations = new Occupations {new Occupation { Type = 5, Description = "Secretary" }};
        listPeson.Add(person1);
        DynamicExport(listPeson);
        Console.ReadLine();
    }

    public static void DynamicExport<T>(List<T> listReg)
    {

        for (int i = 0; i < listReg.Count; i++)
        {
            Console.WriteLine(listReg[i].GetType());
            foreach (var item in listReg[i].GetType().GetProperties())
            {
                Console.WriteLine($"{item.Name}: {item.GetValue(listReg[i], null)}");
            }
        }
    }
}


class Person
{
    public string Name { get; set; }
    public Phones Phones { get; set; }
    public Occupations Occupations { get; set; }
}

class Phones : List<Phone> { }
class Phone
{
    public int Type { get; set; }
    public string Number { get; set; }
}

class Occupations : List<Occupation> { }
class Occupation

{
    public int Type { get; set; }
    public string Description { get; set; }
}

1 个答案:

答案 0 :(得分:0)

我对您的问题进行了一些编辑-希望我能正确理解您。

如果要导出数据

如果您的问题确实与显示数据有关,那么有比创建自己的导出方法更好的方法。您尝试显示的格式类似于YAML。还有JSON和XML。使用这些库之一可能比编写自己的方法要好:

如果您想了解有关反射的更多信息

也许您有兴趣了解有关反射的更多信息,而导出只是其中一个例子。在这种情况下,让我们看一下这一行:

NSObjectProtocol

Console.WriteLine($"{item.Name}: {item.GetValue(listReg[i], null)}"); 最终呼叫$"{item.GetValue(listReg[i], null)}"person1.Phones.ToString()的默认行为仅显示类型名称。您可以像这样覆盖该行为:

ToString

即使您无法在所有可能导出的类中覆盖class Phones : List<Phone> { public override string ToString() { return Program.DynamicExportToString(this); // ... where DynamicExportToString is a modified version of DynamicExport that // builds and returns a string rather than sending it directly to the Console. } } ,也许您仍希望能够处理 any 类。然后,您将需要在ToString方法中添加一些其他逻辑,因为...

DynamicExport

...并非在每种情况下都有效。我们需要根据属性的类型显示不同的内容。

  • 考虑如何处理空值。也许像$"{item.Name}: {item.GetValue(listReg[i], null)}"
  • 如果类型为...,请使用现有的$"{item.Name}: <null>"代码
    • 一个primitive type
    • $"..."
    • DateTime
    • ...或其中一种类型的String
  • 如果该类型实现Nullable<>,则遍历集合的内容,并递归地为每个元素调用导出代码。
    • 在检查类型是否为IEnumerable之后,请务必在 之后检查此接口,因为String实现了String
  • 否则,以该值递归调用导出代码。

当您递归调用导出代码时,最好避免无限循环。如果您要导出的对象包含循环引用,则可以快速结束StackOverflowException。为避免这种情况,请维护一堆已经被访问过的对象。

我认为上述建议通常适用于您使用反射遍历对象图的任何时候-无论是用于序列化还是任何其他目的。 我希望这会有所帮助!