Newbie LINQ Question

D

damiensawyer

Hi, I have the following code extract...


---top---

List<Person> Persons = new List<Person>();
Persons.Add(new Person("Peter", 28,"Perth"));
Persons.Add(new Person("Matthew", 31, "Bundaberg"));
Persons.Add(new Person("Cathryn", 36, "Perth"));


//This works
IEnumerable<Person> p1 = from op in Persons
where op.City=="Perth"
select op;

//Tut this doesn't work
List<Person> p2 = from op in Persons
where op.City == "Perth"
select op;
---bottom---


The compiler error message is: Compiler Error Message: CS0266: Cannot
implicitly convert type
'System.Collections.Generic.IEnumerable<ASP.linq_linqgrouping_aspx.Person>'
to
'System.Collections.Generic.List<ASP.linq_linqgrouping_aspx.Person>'.
An explicit conversion exists (are you missing a cast?)

I'm trying to not get into the habit of using var because I read
somewhere (MSDN) that it makes your code more unreadable to others,
which I tend to agree with.

Can someone please tell me what I'm doing wrong?

Thanks in advance,


Damien
 
F

Frans Bouma [C# MVP]

Hi, I have the following code extract...


---top---

List<Person> Persons = new List<Person>();
Persons.Add(new Person("Peter", 28,"Perth"));
Persons.Add(new Person("Matthew", 31, "Bundaberg"));
Persons.Add(new Person("Cathryn", 36, "Perth"));


//This works
IEnumerable<Person> p1 = from op in Persons
where op.City=="Perth"
select op;

//Tut this doesn't work
List<Person> p2 = from op in Persons
where op.City == "Perth"
select op;
---bottom---


The compiler error message is: Compiler Error Message: CS0266: Cannot
implicitly convert type
'System.Collections.Generic.IEnumerable<ASP.linq_linqgrouping_aspx.Person>'
to
'System.Collections.Generic.List<ASP.linq_linqgrouping_aspx.Person>'.
An explicit conversion exists (are you missing a cast?)

I'm trying to not get into the habit of using var because I read
somewhere (MSDN) that it makes your code more unreadable to others,
which I tend to agree with.

Can someone please tell me what I'm doing wrong?

the 'from op in Persons where op.City == "Perth" select op;' part isn't
a List<Person> but an IEnumerable. If you want to have a List<Person>,
you should do:

List<Person> p2 = (from op in Persons
where op.City == "Perth"
select op).ToList();

The background is that linq to objects, which is what you're using as
'Persons' is an IEnumerable and not an IQueryable containing a Linq
provider, simply does a foreach with a yield over your persons.

so the query is equal to this code:

foreach(Person op in Persons)
[
if(op.City!="Perth")
{
continue;
}
yield return op;
}

which simply produces an IEnumerable<Person> Enumerator, created by the
compiler.

FB

--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 
J

Jon Skeet [C# MVP]

On Jun 20, 8:51 am, "(e-mail address removed)"

I'm trying to not get into the habit of using var because I read
somewhere (MSDN) that it makes your code more unreadable to others,
which I tend to agree with.

I personally find that var *increases* readability rather than
reducing it, but it's a personal thing.
Can someone please tell me what I'm doing wrong?

Exactly what the compiler says - the result of the expression on the
RHS is IEnumerable<Person>, not List<Person>.
If you want it in a List, you should call ToList on the result of the
query expression.

Mind you, if you're *just* using a "where" clause the code would
probably be simpler as:
List<Person> p2 = people.Where(person =>
person.City=="Perth").ToList();

(Note that I've changed "Persons" to "people" to follow naming
conventions and make for more comfortable reading :)

Jon
 
F

Frans Bouma [C# MVP]

Tim said:
You are in pretty good company on that score...

http://www.codinghorror.com/blog/archives/001136.html

'var' is only useful if you really don't know the type. In other
situations, it relies on the IDE to know the type:

var foo = SomeMethod();

vs.

int foo = SomeMethod();

Which one do you prefer? Readability of code is about being able to
understand immediately what's the intention of the code you're reading,
what it does. Knowing what type a variable has is essential. If I have
to mouse over a variable to understand what it is, it takes time plus I
have to rely on the IDE to be able to read the code. If I post the code
on a webpage there's no IDE to help me, also in other areas where IDE
help isn't there, the code should be readable and easy to understand.
'var' doesn't help there.

It's of no surprise that a VB using developer like Atwood likes var, as
VB uses:
Dim foo As New Bar()

which specifies the type once, and C# requires to specify the type
twice: with declaration and at construction. However that doesn't mean
it's better. Better be redundant and see the information TWICE than be
lacking of info and assume the reader will understand. Because that last
thing is the number 1 reason why there are bugs in a lot of code: the
reader assumes things while reading the code but the assumption is
wrong. Simply because we're humans and not a CLR.

FB

--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 
J

Jon Skeet [C# MVP]

Frans Bouma said:
'var' is only useful if you really don't know the type. In other
situations, it relies on the IDE to know the type:

var foo = SomeMethod();

vs.

int foo = SomeMethod();

Which one do you prefer?

Straw man, and easy to provide a counterexample for:

Dictionary<int,List<Person>> peopleByAge =
new Dictionary<int,List<Person>>();

(Yes, I had to wrap onto two lines because it's so long...)

vs

var peopleByAge = new Dictionary<int,List<Person>>();

Which one do you prefer? What's the benefit of the redundancy here?

Sure, "var" isn't suitable for every situation - but there's a massive
difference between that and "it's only useful if you really don't know
the type". If the type is crystal clear from the RHS, I see no benefit
in repeating that information on the LHS.
It's of no surprise that a VB using developer like Atwood likes var, as
VB uses:
Dim foo As New Bar()

which specifies the type once, and C# requires to specify the type
twice: with declaration and at construction. However that doesn't mean
it's better. Better be redundant and see the information TWICE than be
lacking of info and assume the reader will understand.

In what way does my example lack any information? In what way is it not
obvious what the type of peopleByAge is?
 
A

Arne Vajhøj

J

Jon Skeet [C# MVP]

I prefer the first one as we discussed a few weeks ago:

<snip>

And that's fair enough - we can have a reasonable discussion about the
pros and cons of it, even though in the end it's largely a matter of
personal taste. The important thing is that it's a more sensible
example than the one Frans provided. Giving a "worst possible" use of
a feature doesn't give evidence against using that feature in other
situations.

Jon
 
F

Frans Bouma [C# MVP]

Jon said:
<snip>

And that's fair enough - we can have a reasonable discussion about the
pros and cons of it, even though in the end it's largely a matter of
personal taste. The important thing is that it's a more sensible
example than the one Frans provided. Giving a "worst possible" use of
a feature doesn't give evidence against using that feature in other
situations.

That last remark is too generic to be valuable. The main point is that
if you (one in general) give out advice that 'var' is actually often
better, there are serious consequences to be realized as well. Your
dictionary example isn't disturbing me at all, though using 'var' is.
During writing linq queries I often realized I was mousing over
variables to see what type they had. I find that a sign that something
is wrong.

If you aren't disturbed by that, that's of course your own choice,
however do realize that if you have to read code outside VS.NET, you
should be able to do that, easily, and without running the risk of
making assumptions which might not be correct.

FB

--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 
J

Jon Skeet [C# MVP]

        That last remark is too generic to be valuable. The main point is that
if you (one in general) give out advice that 'var' is actually often
better, there are serious consequences to be realized as well. Your
dictionary example isn't disturbing me at all, though using 'var' is.
During writing linq queries I often realized I was mousing over
variables to see what type they had. I find that a sign that something
is wrong.

Would you have to mouse over the variable to find its type with the
"var" case?

I know I find it just as easy to look to the right of the declaration
as to the left. There are far more "grey area" cases of course, where
some people would find a method call's return type obvious and some
wouldn't - but for a constructor call it seems pretty obvious to me.
        If you aren't disturbed by that, that's of course your own choice,

I'd be disturbed if I found myself doing it, but I don't think I'd
start hovering over variables where the constructor call is clearly
visible... unless the declaration wasn't visible either, of course, in
which case it doesn't matter whether you're using var or not.
however do realize that if you have to read code outside VS.NET, you
should be able to do that, easily, and without running the risk of
making assumptions which might not be correct.

Again, would you really not be able to understand the RHS of my
example?

Jon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top