我有一个名为Animals
的类,其中包含两个List<T>
。
一个是熊的清单,一个是企鹅的清单。
我只需通过在Bears
变量上调用animals
就可以轻松地得到熊的列表,但是如何通过反射得到它呢?
我创建了一个静态帮助器类ListHelper
,该类的泛型方法采用Bear
或Pinguin
作为泛型类型,而动物作为应< / 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; }
}
答案 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;
});
}
}