首页 > 解决方案 > 通过反射动态修改 IEnumerable 属性

问题描述

我有各种各样的类,它们具有实现的各种属性IEnumerable(例如IEnumerable<string>,、、IEnumerable<bool>IEnumerable<enum>)。我正在尝试编写一些代码来过滤这些属性的值(例如,如果值是{ "one", "two", "three" }我可能想要过滤 where .Contains("t"))。

这是我所拥有的精髓:

class MyObject
{
    public IEnumerable<string> stringProp { get; set; } = new[] { "one", "two", "three" };
    public IEnumerable<bool> boolProp { get; set; } = new[] { true, false, true };
    public IEnumerable<int> intProp { get; set; } = new[] { 1, 2, 3 };
}

public static void Main(string[] args)
{
    MyObject obj = new MyObject();
    
    foreach (PropertyInfo prop in typeof(MyObject).GetProperties())
    {               
        prop.SetValue(obj, (prop.GetValue(obj) as IEnumerable<dynamic>).Where(val => val != null));
    }
}

问题是,当我尝试将值设置回对象 ( property.SetValue) 时,会引发错误,因为新值是IEnumerable<object>.

Object of type 'System.Linq.Enumerable+WhereArrayIterator`1[System.Object]' cannot be converted to type 'System.Collections.Generic.IEnumerable`1[System.String]'

我已经尝试过Convert.ChangeType,但这不起作用,因为IEnumerable没有实现IConvertible.

我怎么能做到这一点?为什么 LINQWhere查询会更改IEnumerable<dynamic>into IEnumerable<object>

标签: c#reflectiontypespropertyinfodynamictype

解决方案


我理解正确吗?你在寻找这样的东西吗?

var obj = new MyObject();

foreach (var prop in typeof(MyObject).GetProperties())
{
    //assumming all things are IEnumerable<something>
    var type = prop.PropertyType.GenericTypeArguments[0];

    //We can't "instantiate" something as ephemeral as an IEnumerable,
    //so we need something more concrete like a List
    //There might be other ways to filter - this seemed to be the easiest
    var listType = typeof(List<>).MakeGenericType(type);
    var instance = (IList)Activator.CreateInstance(listType);
    
    var currentEnum = (IEnumerable)prop.GetValue(obj);
    foreach (var item in currentEnum)
    {
         if (item != default) // != null would be silly for booleans and ints
         {
             instance.Add(item);
         }
    }

    prop.SetValue(obj, instance);
}

总结:泛型和动态关键字通常不会以这种方式混合使用——动态泛型参数没有任何意义。将动态视为实际上意味着“对象”的东西,但也可以让你写任何你喜欢的东西。当然,IEnumerable<object> 可能更适合作为 IEnumerable。对于具有多个参数的泛型,您最好使用对象甚至更好的特定类。


推荐阅读