如何将一个类型的通用列表转换为一个未知类型的通用列表

4

我希望编写一个函数,它接收一个 List<Object> ,并返回由指定对象类型ObjectType 组成的原始列表 List<ObjectType>。已知原始列表中的对象是ObjectType类型。关键在于找到 ObjectType 的实际类型,这可以使用反射来实现。很抱歉我没有提供代码,但是我确实不知道如何开始编写。

1个回答

11

如果你知道列表中的每个项都是 ObjectType 类型,你可以这样做:

List<object> sourceList = new List<object>() { 1, 2, 3 };
List<int> resultList = sourceList.Cast<int>().ToList();

如果您想以通用方式转换列表中的每个项目,最简单的方法是执行以下操作:
public static IEnumerable<T> ConvertTo<T>(this IEnumerable items)
{
    return items.Cast<object>().Select(x => (T)Convert.ChangeType(x, typeof(T)));
}

这将被实现为扩展方法,因此您可以编写:

List<object> sourceList = new List<object>() { 1, 2, 3 };
List<string> resultList = sourceList.ConvertTo<string>().ToList();

如果目标类型在编译时不可知,您确实需要使用反射。像这样的代码可以正常工作:

class ListUtil
{
    public static List<T> ConvertToList<T>(this IEnumerable items)
    {
        // see method above
        return items.ConvertTo<T>().ToList();
    }

    public static IList ConvertToList(this IEnumerable items, Type targetType)
    {
        var method = typeof(ListUtil).GetMethod(
            "ConvertToList", 
            new[] { typeof(IEnumerable) });
        var generic = method.MakeGenericMethod(targetType);
        return (IList)generic.Invoke(null, new[] { items });
    }
}

现在你可以这样调用它:

List<object> sourceList = new List<object>() { 1, 2, 3 };
IList resultList = ListUtil.ConvertToList(sourceList, typeof(string));
resultList.GetType(); // List<string>

当然,使用这种方法会失去编译时的类型安全。

为什么不直接使用 return items.Cast<T>().ToList(); 呢? - user1914530
@bmused 只有当所有对象都是类型 T 时才有效。这基本上是一个盒子/取消盒子的过程。在我的例子中,使用整数作为输入,.Cast<string>.Cast<double> 将失败。 - p.s.w.g
2
如果类型仅在运行时才知道,则上述方法将无法工作。 - BrokenGlass
@BrokenGlass,请查看我的更新答案,针对只在运行时知道类型的情况提供了解决方案。 - p.s.w.g
我正在寻找你给我的最后一个选项。太棒了!我猜我可以做一个类似的(但可能更复杂)版本来将数组或字典从一种类型转换为另一种类型吗? - Brad Ross
@BradRoss 是的,你可以。通常情况下,你可以使用 MakeGenericMethod 将任何通用方法转换为这样的方法。这往往是支持在运行时传递类型参数的最简单的方法。 - p.s.w.g

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接