繁体   English   中英

我如何获得清单 <T> 通过C#中的反射在类中设置属性?

[英]How do I get a List<T> property in a class via reflection in C#?

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

我可以通过只在animals变量上调用Bears来轻松获得Bears列表-但是如何通过反射得到它呢?

我创建了一个静态帮助器类ListHelper ,该类具有将BearPinguin作为通用类型的通用方法,并且将动物作为参数,如果Bear是通用类型, 则应返回ListHelper列表。

那不会发生。 相反,它崩溃并显示以下消息: 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; }
}

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

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

进行此更改后,您的代码将使我不堪重负。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM