Использование отражения для отображения данных из различных пользовательских классов - PullRequest
0 голосов
/ 09 января 2019

Я хочу создать метод, который отображает информацию, содержащуюся в объекте, которая будет динамически работать с любым объектом. У меня проблемы с обработкой свойств, которые являются другими пользовательскими классами. В приведенном ниже примере Person имеет Phones и Occupations, которые оба являются другими классами. Когда данные отображаются, значение на экране в настоящее время:

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 голосов
/ 09 января 2019

Я внес некоторые правки в ваш вопрос - надеюсь, я вас правильно понял.

Если вы хотите экспортировать данные

Если ваш вопрос действительно касается отображения данных, то есть более эффективные способы сделать это, чем создать собственный метод экспорта. Формат, который вы пытаетесь отобразить, похож на YAML. Там также JSON и XML. Использование одной из этих библиотек, вероятно, лучше, чем написание собственного метода:

Если вы хотите узнать больше об отражении

Может быть, вам интересно узнать больше об рефлексии, и экспорт - всего лишь пример, чтобы поиграть с ним. В этом случае, давайте посмотрим на эту строку:

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

Возможно, вы хотите иметь возможность обрабатывать любой класс , даже если вы не можете переопределить ToString во всех классах, которые вы можете экспортировать. Тогда вам нужно будет добавить дополнительную логику в метод DynamicExport, потому что ...

$"{item.Name}: {item.GetValue(listReg[i], null)}"

... не работает для каждой ситуации. Нам нужно отображать разные вещи в зависимости от типа собственности.

  • Подумайте, как вы хотите обрабатывать нулевые значения. Может быть, что-то вроде $"{item.Name}: <null>"
  • Используйте существующий код $"...", если тип ...
  • Если тип реализует IEnumerable, переберите содержимое коллекции и рекурсивно вызовите код экспорта для каждого элемента.
    • Важно проверить этот интерфейс после вы проверили, является ли тип String, потому что String реализует IEnumerable.
  • В противном случае рекурсивно вызовите ваш код экспорта для этого значения.

Когда вы вызываете свой код экспорта рекурсивно, было бы разумно защититься от бесконечных циклов. Если объект, который вы пытаетесь экспортировать, содержит круговую ссылку - вы можете быстро получить StackOverflowException. Чтобы избежать этого, сохраняйте стопку объектов, которые уже были посещены.

Я думаю, что приведенный выше совет обычно применим всякий раз, когда вы используете отражение для обхода графа объектов - будь то для сериализации или для каких-либо других целей. Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...