Why doesn't strings.Cast<object> cast List<string> to List<object>?
It was suggested in this question, that I could cast a generic collection upward to a collection of objects with .Cast<object>
. After reading up a bit on .Cast<>
, I still can't get it a generic collection to cast into another generic collection. Why doesn't the following work?
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)
{
//...
}
}
}
Answer:
Thank you Reed, here's the code I got to work:
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 s开发者_如何学运维tring 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;
}
}
}
You're misusing Cast<T>
.
First, here:
IEnumerable<string> items = strings.Cast<object>();
When you call strings.Cast<object>()
, this will return IEnumerable<object>
, not IEnumerable<string>
. However, the items in the collection are still strings, but being held in references to objects.
Later, when you want to pass this into a method that takes a List<object>
, you need to turn your IEnumerable<T>
into an IList<T>
. This could easily be done like so:
// Cast to IEnumerabe<object> then convert to List<object>
ProcessCollectionDynamicallyWithReflection(strings.Cast<object>().ToList());
It's because the Cast<>
method does not return a List<T>
type but instead an IEnumerable<T>
. Add a .ToList call to the end and it will fix the problem.
strings.Cast<object>().ToList();
You can also address the casting problem from another perspective: fixing ProcessCollectionDynamicallyWithReflection
since it's unnecessarily restrictive:
private static void ShowItemTypes(IEnumerable items)
{
foreach (object item in items)
{
string itemTypeName = (item != null) ? item.GetType().Name : "null";
Console.WriteLine(itemTypeName);
}
}
This should work:
IEnumerable<object> items = strings.Cast<object>();
Also, you can't pass an IEnumerable as a List into the ProcessCollectionDynamicallyWithReflection without a cast. So, this is even better:
List<object> items = strings.Cast<object>().ToList();
It was suggested in this question, that I could cast a generic collection upward to a collection of objects with
.Cast<object>
No, that is not correct. The Cast
method doesn't cast the collection, it casts each item in the collection, returning a new collection containing the cast values.
You are creating the collection of object, but then you just throw it away as you are not assigning it to a variable. (Well, you are actually throwing away an expression that is capable of creating the collection, but that is not so relevant.)
You need to assign the collection to a variable to keep it, and as you need a List<object>
you need to put the cast items in a list:
List<object> objects = strings.Cast<object>.ToList();
Perhaps you should consider using generics instead of casting to object:
static void ProcessCollectionDynamicallyWithReflection<T>(List<T> items)
That way you can write strongly typed code in the method, and you don't have to create a new collection just to be able to send it to the method.
精彩评论