【问题标题】:How to cast Generic Lists dynamically in C#?如何在 C# 中动态转换通用列表?
【发布时间】:2009-08-21 20:43:20
【问题描述】:

我正在尝试将List<object> 动态转换为List<string>。我尝试了几种方法,但我找不到解决方案。这是一个显示问题的小样本:

List<object> listObject = new List<object>();
listObject.Add("ITEM 1");
listObject.Add("ITEM 2");
listObject.Add("ITEM 3");

List<string> listString = ¿¿listObject??;

提前致谢!

【问题讨论】:

  • 这在版本 4 中也是不可能的,因为“向上转换”或“向下转换”List&lt;T&gt; 都不是类型安全的 - 它是不变的,不是协变的或逆变的。顺便说一句,我已经厌倦了这种错误信息被发布到每个关于集合协/逆变的问题。

标签: c# .net generics list casting


【解决方案1】:

如果您可以使用 LINQ,那么 Cast 方法将满足您的需求:

List<string> listString = listObject.Cast<string>().ToList();

您也可以使用ConvertAll 方法,正如 Stan 在他的回答中指出的那样:

List<string> listString = listObject.ConvertAll(x => (string)x);

如果您不使用 C#3,那么您将需要使用“旧”委托语法而不是 lambda:

List<string> listString =
    listObject.ConvertAll(delegate(object x) { return (string)x; });

【讨论】:

  • @nader:我总是尽量记住,当 LINQ 不可用时,lambda 语法也不可用。
  • 而且只是为了先发制人...我知道 VS2008 可以针对早期版本的 .NET 框架,这将允许使用 lambda 语法但不允许使用 LINQ。但是,根据经验,没有 LINQ 通常也意味着没有 lambda。
【解决方案2】:

如果您使用的是 .NET 3.5,则可以使用,这样您就不必执行额外的 ToList()。如果您需要转换高级对象,您也可以提供自己的转换器。

 List<string> listString = listObject.ConvertAll(x=> x as String);

如果你不能使用 LINQ,你可以这样做

foreach(object item in listObject)
{
  string convertedItem = item as String;
  if(convertedItem != null)
       listString.Add(convertedItem);
}

【讨论】:

  • .NET 2.0 也支持这一点(没有 LINQ,尽管 delgate 语法不太好)。不过请注意,我不相信 .Cast.ToList() 会像您暗示的那样创建一个“额外”列表。它将为结果创建一个新列表,就像您的方法一样
  • 我认为您的意思是 C# 3.0 和 .Net 3.5。
  • @nader:我的意思是 ToList() 做了一个额外的枚举。
  • @Stan:你确定吗? ToList() 将导致枚举,仅此而已。 Cast() 实际上不会枚举集合。
  • @Nader:我很确定 Cast 会枚举一次它以对每个对象执行强制转换,然后 ToList 会进行另一个我相信的枚举(它称为 CopyTo)
【解决方案3】:

这个怎么样:

public static List<T> ConvertToGenericList<T>(IList listOfObjects)
{
    List<T> items = new List<T>();

    for (int i = 0; i < listOfObjects.Count; i++)
    {
        items.Add((T)listOfObjects[i]);
    }
     return items;
}

用法:

List<object> listObject = new List<object>();
listObject.Add("ITEM 1");
listObject.Add("ITEM 2");
listObject.Add("ITEM 3");
List<string> listString = Converter.ConvertToGenericList<string>(listObject);

【讨论】:

    【解决方案4】:

    我不认为你可以一步完成。相反,尝试这样的事情:

            List<object> listObject = new List<object>();
            listObject.Add( "ITEM 1" );
            listObject.Add( "ITEM 2" );
            listObject.Add( "ITEM 3" );
    
            List<string> lstStr = new List<string>( listObject.Count );
    
            foreach ( object obj in listObject )
            {
                lstStr.Add( obj.ToString() );
            }
    

    【讨论】:

    • 这是错误的,他不想将所有 ToString() 都放在该对象上,他想将其转换为字符串对象。从技术上讲,您的示例这次将起作用,但仅适用于字符串。但是如果他碰巧碰到更高级的物体,他就无法使用这种方法了。
    【解决方案5】:
    List<string> listString = (from o in listObject select (string)o).ToList();
    

    【讨论】:

      【解决方案6】:

      我的第一篇文章...希望在我的项目中看起来有用...

              public  dynamic ConvertList(Type CallingType)
          {
      
              dynamic DynamicList;
      
              if (CallingType == TypeOfValue)
              {
                  Type d1 = typeof(List<>);
      
                  Type[] typeArgs = { TypeOfValue };
      
                  Type DynamicListType = d1.MakeGenericType(typeArgs);
      
      
                  object DynamicListObj = Activator.CreateInstance(DynamicListType);
      
      
                  DynamicList = Convert.ChangeType(DynamicListObj, DynamicListType);
      
      
                  foreach (object ValueElement in ValueRange)
                  {
                          dynamic el = Convert.ChangeType(ValueElement, TypeOfValue);
                          DynamicList.Add(el);
                  }
      
              }
              else //retrun empty List but with right type
              {
                  Type d1 = typeof(List<>);
      
                  Type[] typeArgs = { CallingType };
      
                  Type DynamicListType = d1.MakeGenericType(typeArgs);
      
                  object DynamicListObj = Activator.CreateInstance(DynamicListType);
      
                  DynamicList = Convert.ChangeType(DynamicListObj, DynamicListType);
              }
      
              return DynamicList;
          }
      

      我想我还会在某个地方添加一个 try catch。

      如何测试

                      if (PropertyType == typeof(UInt32))
                      {
                          List<UInt32> UInt32_test = NewProperty.ConvertList(PropertyType);
                      }
                      if (PropertyType == typeof(string))
                      {
      
                          List<string> string_test = NewProperty.ConvertList(PropertyType);
                      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-16
        • 1970-01-01
        • 1970-01-01
        • 2015-05-12
        • 1970-01-01
        相关资源
        最近更新 更多