2009-12-02 3 views
3

Было предложено в this question, что я мог бы наложить общую коллекцию вверх на коллекцию объектов с помощью .Cast<object>. После reading up a bit on .Cast<> я до сих пор не могу получить его в общей коллекции, чтобы добавить в другую коллекцию. Почему не работает следующее?Почему не strings.Cast <object> листинг Список <string> в список <object>?

using System.Collections.Generic; 
using System.Linq; 
using System; 

namespace TestCast2343 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<string> strings = new List<string> { "one", "two", "three" }; 

      //gives error: cannot convert from 'System.Collections.Generic.List<string>' 
      //to 'System.Collections.Generic.List<object>' 
      //IEnumerable<string> items = strings.Cast<object>(); 

      //this works 
      strings.Cast<object>(); 

      //but they are still strings: 
      foreach (var item in strings) 
      { 
       System.Console.WriteLine(item.GetType().Name); 
      } 

      //gives error: cannot convert from 'System.Collections.Generic.List<string>' 
      //to 'System.Collections.Generic.List<object>' 
      ProcessCollectionDynamicallyWithReflection(strings); 

      Console.ReadLine(); 
     } 

     static void ProcessCollectionDynamicallyWithReflection(List<object> items) 
     { 
      //... 
     } 
    } 

} 

Ответ:

Спасибо Рид, вот код, который я должен работать:

using System.Collections.Generic; 
using System.Linq; 
using System; 

namespace TestCast2343 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<string> strings = new List<string> { "one", "two", "three" }; 
      List<int> ints = new List<int> { 34, 35, 36 }; 
      List<Customer> customers = Customer.GetCustomers(); 

      ProcessCollectionDynamicallyWithReflection(strings.Cast<object>().ToList()); 
      ProcessCollectionDynamicallyWithReflection(ints.Cast<object>().ToList()); 
      ProcessCollectionDynamicallyWithReflection(customers.Cast<object>().ToList()); 

      Console.ReadLine(); 
     } 

     static void ProcessCollectionDynamicallyWithReflection(List<object> items) 
     { 
      foreach (var item in items) 
      { 
       Console.WriteLine(item.GetType().Name); 
      } 
     } 
    } 

    public class Customer 
    { 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public string Street { get; set; } 
     public string Location { get; set; } 
     public string ZipCode { get; set; } 

     public static List<Customer> GetCustomers() 
     { 
      List<Customer> customers = new List<Customer>(); 
      customers.Add(new Customer { FirstName = "Jim", LastName = "Jones", ZipCode = "23434" }); 
      customers.Add(new Customer { FirstName = "Joe", LastName = "Adams", ZipCode = "12312" }); 
      customers.Add(new Customer { FirstName = "Jake", LastName = "Johnson", ZipCode = "23111" }); 
      customers.Add(new Customer { FirstName = "Angie", LastName = "Reckar", ZipCode = "54343" }); 
      customers.Add(new Customer { FirstName = "Jean", LastName = "Anderson", ZipCode = "16623" }); 
      return customers; 
     } 
    } 
} 

ответ

11

Вы неправильно используете Cast<T>.

Во-первых, здесь:

IEnumerable<string> items = strings.Cast<object>(); 

При вызове strings.Cast<object>(), это вернет IEnumerable<object>, не IEnumerable<string>. Однако элементы в коллекции по-прежнему являются строками, но сохраняются в ссылках на объекты.

Позже, если вы хотите передать это методу, который принимает List<object>, вам необходимо повернуть свой IEnumerable<T> в IList<T>. Это можно легко сделать так:

// Cast to IEnumerabe<object> then convert to List<object> 
ProcessCollectionDynamicallyWithReflection(strings.Cast<object>().ToList()); 
+0

Mesleading: код НЕ превращает 'IEnumerable ' в' List ', он создает * новый *' List' с элементами из 'IEnumerable'. – Guffa

+0

Да. Это не бросок, это полная конверсия. Enumerable.Cast аналогичен, хотя, опять же, не просто одной операции кастинга, а скорее создает новую перечислимую последовательность. –

2

Это потому, что метод Cast<> не возвращает List<T> тип, но вместо этого IEnumerable<T>. Добавьте вызов .ToList до конца, и он устранит проблему.

strings.Cast<object>().ToList(); 
+0

@Downvoter объяснить? – JaredPar

0

Это должно работать:

IEnumerable<object> items = strings.Cast<object>(); 

Кроме того, вы не можете передать IEnumerable как список в ProcessCollectionDynamicallyWithReflection без броска. Таким образом, это еще лучше:

List<object> items = strings.Cast<object>().ToList(); 
0

Было предложено в этом вопросе, , что я мог бросить общий сбор вверх к коллекции объектов с .Cast<object>

Нет, не является правильным. Метод Cast не бросает коллекцию, он бросает каждый элемент в коллекции, возвращая новую коллекцию, содержащую значения литья.

Вы создаете коллекцию объекта, но затем просто удаляете его, поскольку вы не назначаете его переменной. (Ну, вы на самом деле отбрасываете выражение, способное создавать коллекцию, но это не так важно.)

Вам нужно присвоить коллекции переменной, чтобы сохранить его, и как вам нужно List<object> вам нужно поместить элементы отлиты в списке:

List<object> objects = strings.Cast<object>.ToList(); 

Возможно, вам следует рассмотреть возможность использования дженериков вместо литье объекта:

static void ProcessCollectionDynamicallyWithReflection<T>(List<T> items) 

Таким образом, вы можете написать строго типизированный код в методе, и вы не должны создать новую коллекцию только, чтобы иметь возможность отправить его методу.

1

Вы также можете решить проблему литья с другой точки зрения: фиксируя ProcessCollectionDynamicallyWithReflection, так как это излишне ограничительным: уход

private static void ShowItemTypes(IEnumerable items) 
{ 
    foreach (object item in items) 
    { 
     string itemTypeName = (item != null) ? item.GetType().Name : "null"; 
     Console.WriteLine(itemTypeName); 
    } 
} 
Смежные вопросы