将 List<object> 转换为运行时已知的某种类型的列表

Convert List<object> to List of some type known at runtime

我正在尝试将逗号分隔的字符串转换为某种类型的列表。

private static void SetPropertyValue(this object obj, PropertyInfo propInfo, object value)
{
    if (propInfo.PropertyType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(propInfo.PropertyType))
    {
        var listType = propInfo.PropertyType.GetCollectionType();
        var listValue = value.ToString().Split(',').Select(x => Convert.ChangeType(x, listType, null)).ToList();

        propInfo.SetValue(obj, listValue, null);
    }
    
    //....
}

public static Type GetCollectionType(this Type type)
{
    foreach (Type interfaceType in type.GetInterfaces())
    {
        if (interfaceType.IsGenericType &&
            interfaceType.GetGenericTypeDefinition()
            == typeof(IList<>))
        {
            return type.GetGenericArguments()[0];
        }
    }

    throw new ArgumentException("Message is irrelevant");
}

拆分字符串并使用 Convert.ChangeType 转换每个值效果很好,但会创建 List<object>。我需要某种方法来生成 List<PropType> 以便 SetValue 调用正常工作。

如果您使用 List<string> 属性 运行 此代码,您将收到 ArgumentException,因为 List<object> 无法转换为 List<string>.

我通过让我的 SetPropertyValue 方法接受泛型类型 T 并创建 List<T>.

来解决这个问题
public static void SetPropertyValue<T>(object obj, PropertyInfo propInfo, object value)
{
    if (propInfo.PropertyType != typeof(string) && typeof(IEnumerable).IsAssignableFrom(propInfo.PropertyType))
    {
        List<T> listValue = value.ToString()
            .Split(',')
            .Select(x => (T)Convert.ChangeType(x, typeof(T), null))
            .ToList();

        propInfo.SetValue(obj, listValue, null);
    }

    // ...
}

然后我可以使用反射调用方法以将 Type 变量作为 T 传递。

var type = property.PropertyType.GetCollectionType();
var method = typeof(TypeExtensions).GetMethod(nameof(TypeExtensions.SetPropertyValue));
var generic = method.MakeGenericMethod(type);
generic.Invoke(obj, new object[] { obj, property, value });