Как получить свойство List <T>в классе с помощью отражения в C #? - PullRequest
0 голосов
/ 05 сентября 2018

У меня есть класс с именем Animals, который содержит два List<T>. Один - это список медведей, а другой - список пингвинов.

Я могу довольно просто получить список медведей, просто вызвав Bears в переменной animals - но как мне получить это с помощью отражения?

Я создал статический вспомогательный класс ListHelper, с универсальным методом, который принимает Bear или Pinguin в качестве универсального типа, и животных в качестве аргумента, который должен возвращать список медведи, если Bear является универсальным типом.

Этого не происходит. Вместо этого он вылетает с этим сообщением : System.Reflection.TargetException: 'Object does not match target type, и я не могу понять почему, потому что тип правильный, когда я проверяю его через отладчик.

Полностью «рабочий» пример ниже.

using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System;

class ReflectionTrouble
{
    static void Main(string[] args)
    {
        var animals = new Animals
        {
            Bears = new List<Bear> {new Bear {Name = "Bear1"}, new Bear {Name = "Bear 2"}},
            Pinguins = new List<Pinguin> {new Pinguin {Name = "Pingo1"}, new Pinguin {Name = "Pingo2"}}
        };

        var lists = ListHelper.GetList<Bear>(animals);
        foreach (var bear in lists)
        {
            Console.WriteLine(bear.Name);
        }
        //expected to have printed the names of the bears here...
    }
}

public static class ListHelper
{
    public static IEnumerable<T> GetList<T>(Animals animals)
    {
        var lists = animals.GetType().GetRuntimeProperties().Where(p => p.PropertyType.IsGenericType);
        foreach (var propertyInfo in lists)
        {
            var t = propertyInfo.PropertyType;
            var typeParameters = t.GetGenericArguments();
            foreach (var typeParameter in typeParameters)
            {
                if (typeParameter == typeof(T))
                {
                    // This is where it crashes.
                    var list = (IEnumerable<T>) propertyInfo.GetValue(t);
                    return list;
                }
            }
        }

        return Enumerable.Empty<T>();
    }
}


public class Animals
{
    public IList<Bear> Bears { get; set; }

    public IList<Pinguin> Pinguins { get; set; }
}

public class Bear
{
    public string Name { get; set; }
}

public class Pinguin
{
    public string Name { get; set; }
}

Ответы [ 2 ]

0 голосов
/ 05 сентября 2018

Я думаю, что словарь был бы лучшим решением здесь вместо отражения. Из коробки словарь должен быть в состоянии обработать все ваши сценарии и предложить гораздо лучшую производительность. Если вы хотите включить его в класс, он может выглядеть следующим образом.

public interface IAnimal
{
    string Name { get; set; }
}

public class Animals
{
    private readonly ConcurrentDictionary<Type, IList<IAnimal>> AnimalDictionary;
    public Animals(IList<IAnimal> animals)
    {
        this.AnimalDictionary = new ConcurrentDictionary<Type, IList<IAnimal>>();
        this.Add(animals);
    }

    public Animals(IAnimal animal)
    {
        this.AnimalDictionary = new ConcurrentDictionary<Type, IList<IAnimal>>();
        this.Add(animal);
    }

    public IList<IAnimal> Get<T>() where T : IAnimal
    {
        if (this.AnimalDictionary.ContainsKey(typeof(T)))
        {
            return this.AnimalDictionary[typeof(T)];
        }
        return (IList <IAnimal>)new List<T>();
    }

    public void Add(IList<IAnimal> animals)
    {
        foreach (IAnimal animal in animals)
        {
            this.Add(animal);
        }
    }

    public void Add(IAnimal animal)
    {
        this.AnimalDictionary.AddOrUpdate(animal.GetType(),
            new List<IAnimal>{animal}, 
            (type, list) =>
                {
                     list.Add(animal);
                     return list;
                });
    }
}
0 голосов
/ 05 сентября 2018

Вы неправильно понимаете, как позвонить propertyInfo.GetValue. Параметр, который вы передаете ему, должен быть объектом, значение свойства которого вы хотите получить. Так что в этом случае вы хотите узнать значение свойства для животных, чтобы эта строка была:

var list = (IEnumerable<T>) propertyInfo.GetValue(animals);

С этим изменением твой код возвращает мне медведей.

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