【问题标题】:Convert List<object> to List<Type>, Type is known at runtime将 List<object> 转换为 List<Type>,类型在运行时已知
【发布时间】:2014-04-08 14:07:35
【问题描述】:

我正在实施某种反序列化并遇到下一个问题:

我有List&lt;object&gt;System.Reflection.Field,它的FieldType可以是List&lt;string&gt;List&lt;int&gt;List&lt;bool&gt;,所以我需要从List&lt;object&gt;转换为这些类型。

public static object ConvertList(List<object> value, Type type)
{
   //type may be List<int>, List<bool>, List<string>
}

我可以分别编写每个案例,但应该有更好的方法使用反射。

【问题讨论】:

    标签: c# system.reflection


    【解决方案1】:

    我相信你想要的是:

    public static object ConvertList(List<object> value, Type type)
    {
        var containedType = type.GenericTypeArguments.First();
        return value.Select(item => Convert.ChangeType(item, containedType)).ToList();
    }
    

    示例用法:

    var objects = new List<Object> { 1, 2, 3, 4 };
    
    ConvertList(objects, typeof(List<int>)).Dump();
    

    我不确定这有多大用处……它突出了我猜想的非常有用的 Convert.ChangeType 方法!


    更新: 由于其他人已经正确指出这实际上并没有返回 List&lt;T&gt;(其中 T 是有问题的类型),因此可能无法完全回答手头的问题,我已选择提供更新的答案:

    public static object ConvertList(List<object> items, Type type, bool performConversion = false)
    {
        var containedType = type.GenericTypeArguments.First();
        var enumerableType = typeof(System.Linq.Enumerable);
        var castMethod = enumerableType.GetMethod(nameof(System.Linq.Enumerable.Cast)).MakeGenericMethod(containedType);
        var toListMethod = enumerableType.GetMethod(nameof(System.Linq.Enumerable.ToList)).MakeGenericMethod(containedType);
    
        IEnumerable<object> itemsToCast;
    
        if(performConversion)
        {
            itemsToCast = items.Select(item => Convert.ChangeType(item, containedType));
        }
        else 
        {
            itemsToCast = items;
        }
    
        var castedItems = castMethod.Invoke(null, new[] { itemsToCast });
    
        return toListMethod.Invoke(null, new[] { castedItems });
    }
    

    如果您不需要转换(因此每个值的类型实际上是正确的,并且字符串中没有整数等),则删除 performConversion 标志和相关块。


    示例:https://dotnetfiddle.net/nSFq22

    【讨论】:

    • 这不会创建特定类型的通用列表。它只是将内部元素转换为特定类型,但列表本身仍然是List&lt;object&gt;。见:dotnetfiddle.net/Hd4y1c
    • 只是为了摆脱"Cast""ToList" 的神奇字符串,您可以将它们替换为nameof(Enumerable.Cast)nameof(Enumerable.ToList)
    【解决方案2】:

    不确定这是否有帮助,但您可以使用 Linq Cast 吗?

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

    【讨论】:

    • 为什么这不是更多的投票?这似乎是管理和清洁的最简单的解决方案!
    • 这似乎可以直接使用。我会推荐这个。
    • theList.Cast&lt;int&gt;() 为我返回 IEnumerable&lt;int&gt;,而不是 List&lt;int&gt;
    • 好点。你需要在.Cast&lt;int&gt;()之后.ToList()
    • 这是一个很好的解决方案,但它没有回答原始问题 - 类型在运行时已知,您将如何处理?
    【解决方案3】:

    类型只在运行时知道,所以我猜泛型方法不是可行的方法

    public static object ConvertList(List<object> value, Type type)
    {
       IList list = (IList)Activator.CreateInstance(type);
       foreach (var item in value)
       {
          list.Add(item);
       }
       return list;
    }
    

    【讨论】:

    • 是的,这是一个很好的解决方案。在这里找到好线程 -stackoverflow.com/questions/2474119/dynamic-listt-type
    • 我不确定这是否适用于 OP 提到的类型(至少是 bool 和 int),因为首先要创建对象列表,值类型已被装箱,因此无法添加到列表中。编辑:实际上这不是问题。您需要将方法中的Type[] typeArgs = { type }; 更改为Type[] typeArgs = { type.GenericTypeArguments.First() };;
    • @Richiban 你是对的,我错误地认为type 是项目的类型。固定
    【解决方案4】:
        /// <summary>
        /// Converts list of items into typed list of item of new type
        /// </summary>
        /// <example><code>
        /// Consider source to be List<object>, newItemType is typeof(string), so resulting list wil have type List<string>
        /// </code></example>
        /// <param name="newItemType">New item type</param>
        /// <param name="source">List of objects</param>
        /// <returns>Typed List object</returns>
        public static IList ConvertList(Type newItemType, IList source)
        {
            var listType = typeof(List<>);
            Type[] typeArgs = { newItemType };
            var genericListType = listType.MakeGenericType(typeArgs);
            var typedList = (IList)Activator.CreateInstance(genericListType);
            foreach (var item in source)
            {
                typedList.Add(item);
            }
            return typedList;
        }
    

    【讨论】:

      【解决方案5】:
       public static object ConvertList<T>(List<object> value) where T : class
          {
              var newlist = value.Cast<T>().ToList();
              return newlist;
          }
      

        public static List<T> ConvertList<T>(List<object> value) where T : class
          {
              List<T> newlist = value.Cast<T>().ToList();
              return newlist;
          }
      

      【讨论】:

        【解决方案6】:

        试试这个:

        public static List<T> ConvertList<T>(List<object> list)
        {
            List<T> castedList = list.Select(x => (T)x);
            return castedList;
        }
        

        呼叫:

        List<object> myList = new List<object> {"test", "foo", "bar"};
        List<string> stringList = ConvertList<string>(myList);
        

        【讨论】:

        • 我如何理解我应该调用 ConvertList?我只知道Type,我不会输入ConvertList
        【解决方案7】:
        public static List<T> ConvertType<T>(List<object> list) {
            var list2 = new List<T>();
            for(int i=0;i<list.Count;i++) list2.Add((T)list[i]);
            return list2;
        }
        

        【讨论】:

        • 我如何理解我应该调用 ConvertList?我只知道Type,我不会输入ConvertList
        • 我明白了,那么您需要在运行时使用反射来制作泛型类型,请参阅 Guillaume 的回答(我不会重复)。
        【解决方案8】:

        这是一个类似于 linq 扩展方法的扩展方法,不同之处在于它采用类型参数而不是类型参数:

        public static IList CastToList(this IEnumerable source, Type itemType)
        {
            var listType = typeof(List<>).MakeGenericType(itemType);
            var list = (IList)Activator.CreateInstance(listType);
            foreach (var item in source) list.Add(item);
            return list;
        }
        

        用法:

        var list = new List<object>();
        list.add(1);
        list.add(2);
        var boxedIntList = list.CastToList(typeof(int)); //type is object{List<int>}
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-12-01
          • 2022-11-02
          • 2020-07-05
          • 1970-01-01
          • 2018-11-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多