views:

237

answers:

4

Hi

I would like to convert List<Company> to List<ICompany>

ICompany is an interface which Company implements.

public List<ICompany> FindAll()
{
    List<Company> companies = new List<Company>();

    var query = from c in _scope.Extent<Company>()
                select c;

    companies = query.ToList();

    return companies.ToList<ICompany>(); // doesn't work
    //and
    return companies.ToList(); // doesn't work
}

Any thoughts?

+23  A: 

Use Enumerable.Cast:

return query.Cast<ICompany>().ToList();

A few comments:

List<Company> companies = new List<Company>();

This creates a new list. But you never use it because two lines later you have

companies = query.ToList();

overwriting the list that you created (and in the intermediate line you never refer to companies). If you want, you can declare and obtain the results in one fell swoop:

List<Company> companies = query.ToList();

Second, all this is unnecessary if you're just trying to return a list of the results. Brevity (to an extent) is a big plus in programming. "Less is more" is the saying as less code means less code to write, less code to test and less code to maintain. Instant productivity increase by writing less code! Here's a short version of your method:

public List<ICompany> FindAll() {
    var query = from c in _scope.Extent<Company>()
                select c;
    return query.Cast<ICompany>().ToList();
}

or even

public List<ICompany> FindAll() {
    return _scope.Extent<Company>().Cast<ICompany>().ToList();
}

Third, at a minimum, you should consider returning an IList instead of List. It is better to code to interfaces rather than concrete types. This decouples your code from implementation details making the code more amenable to change and easier to test.

Lastly, you should examine if you really need to return a List. What methods on list are you using? If you merely are using it to enumerate the results (foreach(var item in list)) then you should instead return an IEnumerable<ICompany>:

public IEnumerable<ICompany> FindAll() {
    return _scope.Extent<Company>().Cast<ICompany>();
}
Jason
+1 for the nice explanation (and tweaking based on the last comment...)
Reed Copsey
Yes, thanks for pointing that out which caused me to give his code a much closer inspection than I initially did.
Jason
Great review. Perhaps it is because I am stuck in 2.0 land, but is a 'return' not needed?
g .
@g.: Oops. Thanks!
Jason
+3  A: 
return companies.Cast<ICompany>().ToList(); 
spender
A: 

If for some reason you don't want to use Enumerable.Cast (though I would recommend doing so along with the other comments) you could always do this:

companies = query.ToList();
List<ICompany> ret = new List<ICompany>();
foreach (Company c in companies) 
{
   ret.Add(c as ICompany);
}

It's pretty much the same solution as Skeolan's, but if (ICompany)c failes it throws. In my code, c as ICompany will return null if the cast fails.

Ari Roth
+1  A: 

In addition to the Enumerable.Cast answers, if you find yourself going between collections of Company and ICompany a lot, another suggestion might be to derive your own collection class from Collection<T> called CompanyCollection and have it implement IList<ICompany>.

If you were using .NET 4.0 (currently in beta) you could take advantage of generic covariance which allows you to do this more implicitly.

Josh Einstein
+1 for mentioning covariance (and being surprised by the fact that this is the only answer that does)
Tamás Szelei