如何通过C#中的反射获取类中的List <t>属性?

时间:2018-09-05 15:25:41

标签: c# reflection

我有一个名为Animals的类,其中包含两个List<T>。 一个是熊的清单,一个是企鹅的清单。

我只需通过在Bears变量上调用animals就可以轻松地得到熊的列表,但是如何通过反射得到它呢?

我创建了一个静态帮助器类ListHelper,该类的泛型方法采用BearPinguin作为泛型类型,而动物作为应< / em>如果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 :(得分:1)

您误会了如何致电propertyInfo.GetValue。传递给它的参数应该是要获取其属性值的对象。因此,在这种情况下,您需要动物的属性值,因此该行应为:

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

通过此更改,您的代码还让我负担了。

答案 1 :(得分:0)

我认为在这里,词典比反射更好。开箱即用的字典应该能够处理所有情况,并提供更好的性能。如果要将其封装在类中,则它可能看起来像这样。

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