通过反射动态修改IEnumerable属性

问题描述

我有许多类,这些类具有实现IEnumerable的各种属性(例如IEnumerable<string>IEnumerable<bool>IEnumerable<enum>等)。我正在尝试编写一些代码来筛选这些属性的值(例如,如果值为{ "one","two","three" },则可能要筛选.Contains("t")的位置)。

这是我所拥有的精髓:

class MyObject
{
    public IEnumerable<string> stringProp { get; set; } = new[] { "one","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,因此无法正常工作。

我该怎么做?为什么LINQ Where查询IEnumerable<dynamic>更改为IEnumerable<object>

解决方法

我理解正确吗?您是否正在寻找类似的东西?

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

摘要:泛型和dynamic关键字通常不会以这种方式混合-使用动态泛型参数是没有意义的。将动态视为实际上意味着“对象”的东西,但也可以让您根据自己的喜好编写任何东西。当然,IEnumerable 可能比IEnumerable更好。对于具有多个参数的泛型,最好使用对象,甚至最好使用特定的类。