Easy way* to cast an object in a LINQ query? Methinks not*

R

raylopez99

Inspired by Chapter 8 of Albahari's excellent C#3.0 in a Nutshell
(this book is amazing, you must get it if you have to buy but one C#
book) as well as Appendix A of Jon Skeet's book, I am going through
some LINQ queries. But how to cast? (

See the below, modified from somebody else's code.

The problem is the query 'stops' (throws a cast exception) at "3", and
never gets to "violet".

How to prevent this?

Pseudocode OK, just a hint is all I need, but more of course is
better.

RL

*PS--by "easy way to cast" I mean something very short, that can work
at runtime, not something like a CASE/SWITCH statement that lists all
possibilities ahead of time, but, I'll take all answers.

//


List<object> words = new List<object> { "green", "blue", 3, "violet",
5 };

// Cast the objects in the list to type 'string'
// and project the first two letters of each string.

try
{
IEnumerable<string> query =
words.AsQueryable().Cast<string>().Select(str => str.Substring(0, 2));

foreach (string s in query)
Console.WriteLine(s);
}

catch (ArgumentException ex)
{
Console.WriteLine(ex);
}
catch (InvalidCastException ex2)
{
Console.WriteLine("invalid cast!" + ex2);
}

/* This code *should* produce the following output, but
it breaks out of the query when it gets to '3' above and throws an
InvalidCastException--how to get it to complete the query until the
end?

gr
bl
vi
*/

RL
 
F

Family Tree Mike

I suggest a change your critical line to:

IEnumerable<string> query =
words.AsQueryable().Cast<string>().Select(str => str.Substring(0,
Math.Min(str.Length, 2)));
 
J

Jon Skeet [C# MVP]

raylopez99 said:
Inspired by Chapter 8 of Albahari's excellent C#3.0 in a Nutshell
(this book is amazing, you must get it if you have to buy but one C#
book) as well as Appendix A of Jon Skeet's book, I am going through
some LINQ queries. But how to cast? (

See the below, modified from somebody else's code.

The problem is the query 'stops' (throws a cast exception) at "3", and
never gets to "violet".

How to prevent this?

See the "OfType" method.
 
F

Family Tree Mike

By the way, the reason I said this is that I don't get an invalid cast, but
rather
an index out of range error...
 
R

raylopez99

Family said:
I suggest a change your critical line to:

IEnumerable<string> query =
words.AsQueryable().Cast<string>().Select(str => str.Substring(0,
Math.Min(str.Length, 2)));

FTM--that didn't do anything important (or so it seems, but I left it
in anyway, figuring you must be guarding against something), i.e., you
still got the exception thrown. What was it supposed to guard
against?

Anyway, I took Jon Skeet's idea to mind, and here is what worked. I
have a feeling the extra ".Cast<>" below is redundant...but don't see
a problem leaving it in.

RL

//this worked...add-- OfType<string>(). in the middle as shown

IEnumerable<string> query =
words.AsQueryable().OfType<string>().Cast<string>().Select(str =>
str.Substring(0,Math.Min(str.Length, 2)));
 
R

raylopez99

I see...index out of range would be if you did not put an index that's
within the string length...makes sense... so ignore my question to you
in the prior post.

Thank you.
 
F

Family Tree Mike

Just so we are clear, now I get no exceptions within this code, and the
output is:

gr
bl
3
vi
5
 
R

raylopez99

Yes, thanks, that worked "OfType".

I'm getting the hang of this Linq. Con permission, I would like to
upload your Appendix A and also Albahari's Linq examples from Chapter
8 of his excellent book "C#3.0 in a Nutshell". A little cheat sheet
of Linq, since otherwise you have to buy a huge 1000 page tome (which
I've ordered as well).

If you're worried about copyright infringement I can work the examples
some to make them 'unique', per our conversation about artistic
license. Besides it's well known that supplying examples on the web
will increase print sales...

I like your book--so far up to p. 62 "Part 2".

The best part so far IMO:

- Listing 2.1 Using Delegates in a variety of simple ways. The best
explanation of delegates I've seen so far, but, I will say by now I am
pretty familiar with delegates / events so maybe that's why (with
hindsight it seems so easy). But I'd never seen .Invoke in delegate
before your book (normally it's not mentioned, since implicit).

- p. 54 "Summary of Value types and Reference types" - this was good,
but this *key* sentence should be amplified IMO "When a reference type
is used as a method parameter, by default the parameter is passed _by
value_--but the value itself is a reference". You should highlight
and expound on "but the value itself is a reference" IMO because this
is where newbies like me get confused. You should add--"..and in C#,
you can change a reference type variable calling a method through a
reference passed by value to a method, in exactly the same way as
through a reference type passed by reference to the method, so long as
'new' is not used in the method". Well, that's the idea, perhaps you
can break up this compound sentence. What threw me (from a C++
background) is the fact that they use copy constructors and const in C+
+ and I thought that 'pass by value' (for a reference type variable)
meant a 'copy' that doesn't change the original--I'm sure other
newbies have made this mistaken assumption too.

Other stuff I like but I'll get to it later maybe.

And Func (p.56) too I now like--now I get it--Albahari on p. 119 also
discusses this useful syntax.
 
J

Jon Skeet [C# MVP]

Yes, thanks, that worked "OfType".

Why are you calling AsQueryable() by the way?
I'm getting the hang of this Linq.  Con permission, I would like to
upload your Appendix A and also Albahari's Linq examples from Chapter
8 of his excellent book "C#3.0 in a Nutshell".  A little cheat sheet
of Linq, since otherwise you have to buy a huge 1000 page tome (which
I've ordered as well).

No, I'd rather you didn't do that. You'd have to ask Joe/Ben about C#
in a Nutshell, although it's worth checking whether the examples are
already available in downloadable source code.
If you're worried about copyright infringement I can work the examples
some to make them 'unique', per our conversation about artistic
license.  Besides it's well known that supplying examples on the web
will increase print sales...

That's a matter for myself and Manning to work out, however. Yes, I
like appendix A as well and think it's useful - but I would rather you
didn't take it upon yourself to publish it. If Manning and I choose to
make that available for free (there are already a couple of chapters
downloadable for free) then that's our decision to take. I will
mention it to the publisher though.

In terms of cheat sheets, you might want to look at http://refcardz.dzone.com
I like your book--so far up to p. 62 "Part 2".

The best part so far IMO:

- Listing 2.1 Using Delegates in a variety of simple ways.  The best
explanation of delegates I've seen so far, but, I will say by now I am
pretty familiar with delegates / events so maybe that's why (with
hindsight it seems so easy).  But I'd never seen .Invoke in delegate
before your book (normally it's not mentioned, since implicit).

I'm glad you're getting more comfortable with them - although I wish
you'd step away from the idea that they're like GOTO statements
(they're really not).
- p. 54 "Summary of Value types and Reference types" - this was good,
but this *key* sentence should be amplified IMO "When a reference type
is used as a method parameter, by default the parameter is passed _by
value_--but the value itself is a reference".  You should highlight
and expound on "but the value itself is a reference" IMO because this
is where newbies like me get confused.  You should add--"..and in C#,
you can change a reference type variable calling a method through a
reference passed by value to a method, in exactly the same way as
through a reference type passed by reference to the method, so long as
'new' is not used in the method".  Well, that's the idea, perhaps you
can break up this compound sentence.  What threw me (from a C++
background) is the fact that they use copy constructors and const in C+
+ and I thought that 'pass by value' (for a reference type variable)
meant a 'copy' that doesn't change the original--I'm sure other
newbies have made this mistaken assumption too.

I originally had quite a long example with a blow-by-blow explanation
- I can't remember how much of it is still there. However, it's very
difficult to make this topic clear - I found your explanation above
very confusing (particularly uses of the word "through"). I have yet
to discover the "perfect" way of explaining the whole business (which
goes much deeper than just method parameters - it's fundamental to how
you understand variables, garbage collection, assignment, etc). I
haven't seen anyone else do a stellar job of explaining it either,
otherwise I'd defer to them. It's one of those things that just takes
a while before the lightbulb comes on.
Other stuff I like but I'll get to it later maybe.

And Func (p.56) too I now like--now I get it--Albahari on p. 119 also
discusses this useful syntax.

Not sure exactly what you're referring too - Func is a delegate type,
not a piece of syntax. I guess you mean either lambda expressions or
anonymous methods, but I don't have the book with me right now, so I
can't really tell.

Jon
 
R

raylopez99

Why are you calling AsQueryable() by the way?

I don't know--it was in the code I copied. I took it out and the
query works fine. Also I took out the cast and it works fine, but
raises a question**.

Here is the reduced query that works:

IEnumerable<string> query = words.OfType<string>().Select(str =>
str.Substring(0, Math.Min(str.Length, 2)));

**BTW, I found something of interest today. You can break a query
into two (see *below for an example), but, a question is raised:

if you have two queries separate, then the first one can trigger an
exception before the second one can override. What I mean is this:

it seems that in this query:
IEnumerable<string> query =
words.OfType<string>().Cast<string>().Select(str => str.Substring(0,
2));

That the OfType<string>() 'overrides' the Cast<> (because it seems
that with this functional type expression the final expression is not
evaluated until everything on the RHS is run). Thus you never get the
Exception thrown by .Cast<>, because .OfType<> overrides it.

But, if you were to break up this into two queries, what would
happen? Time to find out...wait...

OK, just as I thought: the exception is thrown! The *disadvantage*
of using multiple queries rather than all in one line.

Here it is:

// List<object> words = new List<object> { "green",
"blue", 3, "violet", 5 };

IEnumerable<string> query1 =
words.Cast<string>().Select(str => str.Substring(0,
Math.Min(str.Length, 2))); //breaking up original query into 'query1'
and 'query2'

IEnumerable<string> query2 =
query1.OfType<string>(); // this is legal

foreach (string s in query2) //runtime error! since
query1 fails (throws an exception at element '3')

//ironically, breaking up the original query into two queries results
in a runtime error; had we left the original query alone we'd be
fine.


Another valuable contribution to theory.

No, I'd rather you didn't do that. You'd have to ask Joe/Ben about C#
in a Nutshell, although it's worth checking whether the examples are
already available in downloadable source code.


OK, no worries. Don't bother yourself asking, I just thought it would
be useful. You realize your publisher is like a wedding photographer
with your wedding pictures...if they're nice, it's not a problem, but
if they become hostile...
In terms of cheat sheets, you might want to look athttp://refcardz.dzone.com

Excellent. Thanks I signed up and downloaded them, very nice.
I'm glad you're getting more comfortable with them - although I wish
you'd step away from the idea that they're like GOTO statements
(they're really not).

OK but they are "in my mind's eye".
I originally had quite a long example with a blow-by-blow explanation
- I can't remember how much of it is still there. However, it's very
difficult to make this topic clear - I found your explanation above
very confusing (particularly uses of the word "through"). I have yet
to discover the "perfect" way of explaining the whole business (which
goes much deeper than just method parameters - it's fundamental to how
you understand variables, garbage collection, assignment, etc). I
haven't seen anyone else do a stellar job of explaining it either,
otherwise I'd defer to them. It's one of those things that just takes
a while before the lightbulb comes on.

OK, that's interesting. I use the word "through" loosely, since I
never have figured out the convention in "calling method" or "called
method" or whatever. One code calls the other, I think the method,
like a procedure/sub procedure. Anyway, that's how I call it (mind's
eye).
Not sure exactly what you're referring too - Func is a delegate type,
not a piece of syntax. I guess you mean either lambda expressions or
anonymous methods, but I don't have the book with me right now, so I
can't really tell.

Thanks. Also your book reviews are helpful. I think Albahari et al.
C# Nutshell reference book is the best C# book ever. Packed w/
information. Also useful is the C# Recipe book by O'Reilly.


Goodbye,

RL

** // example showing a query broken up into two queries
for readability

string[] names = { "Tom", "Dick", "harry" };
IEnumerable<string> filteredNames1 =
System.Linq.Enumerable.Where(names, n => n.Length >= 4);

foreach (string n in filteredNames1)
Console.Write(n + "|"); //Dick|Harry|

IEnumerable<string> filteredNames2 =
System.Linq.Enumerable.Where(filteredNames1, n => n.Length <= 4);
Console.WriteLine("\n");
foreach (string n in filteredNames2)
Console.WriteLine(n + "|"); //Dick
 
M

Marc Gravell

You have reversed the query; your query2 is equivalent to:

words.Cast<string>().Select(str => str.Substring(0, Math.Min(str.Length,
2))).OfType<string>();

not the original:

words.OfType<string>().Cast<string>().Select(str => str.Substring(0,
2));

The order is important.
 
J

Jon Skeet [C# MVP]

I don't know--it was in the code I copied.  I took it out and the
query works fine. Also I took out the cast and it works fine, but
raises a question**.

Here is the reduced query that works:

IEnumerable<string> query = words.OfType<string>().Select(str =>
str.Substring(0, Math.Min(str.Length, 2)));

Yup, that'll work fine.
**BTW, I found something of interest today.  You can break a query
into two (see *below for an example), but, a question is raised:

if you have two queries separate, then the first one can trigger an
exception before the second one can override.  What I mean is this:

it seems that in this query:
IEnumerable<string> query =
words.OfType<string>().Cast<string>().Select(str => str.Substring(0,
2));

That the OfType<string>() 'overrides' the Cast<> (because it seems
that with this functional type expression the final expression is not
evaluated until everything on the RHS is run).  Thus you never get the
Exception thrown by .Cast<>, because .OfType<> overrides it.

It doesn't "override" it - it's just earlier in the data pipeline.
Cast asks OfType for data, and OfType will never provide it with
anything other than the right type, so no exception is thrown.
But, if you were to break up this into two queries, what would
happen?  Time to find out...wait...

OK, just as I thought:  the exception is thrown!  The *disadvantage*
of using multiple queries rather than all in one line.

Here it is:

              // List<object> words = new List<object> { "green",
"blue", 3, "violet", 5 };

                IEnumerable<string> query1 =
words.Cast<string>().Select(str => str.Substring(0,
Math.Min(str.Length, 2))); //breaking up original query into 'query1'
and 'query2'

                IEnumerable<string> query2 =
query1.OfType<string>(); //  this is legal

You've done that the wrong way round though. If you keep the query in
the same logical order (words -> OfType -> Cast -> Select) then you'll
get the same result however you break it up. You've changed the order
to words -> Cast -> Select -> OfType, so of course it's going to
break.
                foreach (string s in query2) //runtime error! since
query1 fails (throws an exception at element '3')

//ironically, breaking up the original query into two queries results
in a runtime error; had we left the original query alone we'd be
fine.

It's the reordering which is a problem, not the breaking up. The
reordering would also have been a problem if you'd kept it as a single
query.

OK, no worries.  Don't bother yourself asking, I just thought it would
be useful.  You realize your publisher is like a wedding photographer
with your wedding pictures...if they're nice, it's not a problem, but
if they become hostile...

They won't become hostile just because of that suggestion.
OK but they are "in my mind's eye".

You use that phrase whenever you're basically wrong. Your "mind's eye"
could regard integers and strings as the same thing, it wouldn't make
it true. Ironically, you seem to have originally started with the
whole GOTO idea when considering something very different -
continuation passing.
OK, that's interesting.  I use the word "through" loosely, since I
never have figured out the convention in "calling method" or "called
method" or whatever.  One code calls the other, I think the method,
like a procedure/sub procedure.  Anyway, that's how I call it (mind's
eye).

Using terms loosely is a recipe for disaster, IMO. That's why my
discussion of delegates is often quite tortuous - keeping "delegate
instance" and "delegate type" distinct makes for wordy sentences, but
precise ones.
Thanks. Also your book reviews are helpful.  I think Albahari et al.
C# Nutshell reference book is the best C# book ever.  Packed w/
information.  Also useful is the C# Recipe book by O'Reilly.

Haven't looked at the C# Recipe book. Lots more books to review... (I
don't think anyone can really say what "the best C# book ever" is
until they've read *all* of them, by the way.)

Jon
 
R

raylopez99

You have reversed the query; your query2 is equivalent to:

words.Cast<string>().Select(str => str.Substring(0, Math.Min(str.Length,
2))).OfType<string>();

not the original:

words.OfType<string>().Cast<string>().Select(str => str.Substring(0,
2));

The order is important.

IEnumerable<string> query2 = OfType<string>().query;

Hi,

This will not compile. ANy other ideas?

RL
 
R

raylopez99

Haven't looked at the C# Recipe book. Lots more books to review... (I
don't think anyone can really say what "the best C# book ever" is
until they've read *all* of them, by the way.)

If you have the MSDN site link that loads when you load the Help in VS
(the front page) pls let me know--once your review was listed there.
For some reason I lost it and now I can't find it despite Google.

RL
 
J

Jon Skeet [C# MVP]

 IEnumerable<string> query2 = OfType<string>().query;

This will not compile.  ANy other ideas?

Why would you expect that to compile? "query" isn't a member of
IEnumerable<T> which is returned by OfType<string> and you need
something to call OfType<string> on in the first place.

I suggest you take a step back and try to understand extension methods
better so you can really pick apart what's going on in a LINQ query.
Experimenting by randomly reordering bits of code is going to be a
very time-consuming way of gaining any sort of understanding.

Jon
 
J

Jon Skeet [C# MVP]

If you have the MSDN site link that loads when you load the Help in VS
(the front page) pls let me know--once your review was listed there.
For some reason I lost it and now I can't find it despite Google.

All my book reviews appear on my blog:
http://msmvps.com/jon.skeet

Some of them will appear on the VS C# channel, but not all - and I
won't always be able to predict which.

Jon
 
R

raylopez99

Why would you expect that to compile? "query" isn't a member of
IEnumerable<T> which is returned by OfType<string> and you need
something to call OfType<string> on in the first place.

I suggest you take a step back and try to understand extension methods
better so you can really pick apart what's going on in a LINQ query.
Experimenting by randomly reordering bits of code is going to be a
very time-consuming way of gaining any sort of understanding.

Yes, but if you were truly competent and/or the answer was easy you
could have typed in a short answer, which would have been helpful.

Oh well, I guess we'll never know.

I might order the LINQ book (the 1000 pager you recently reviewed)
since LINQ appears more difficult than I thought.

RL
 
J

Jon Skeet [C# MVP]

raylopez99 said:
Yes, but if you were truly competent and/or the answer was easy you
could have typed in a short answer, which would have been helpful.

It's unclear what you're trying to do. Breaking up the query is easy,
but not like that - and just experimenting haphazardly isn't going to
help you. However, I see that once more you've retreated into ad
hominem attacks.
Oh well, I guess we'll never know.

Never know what? It's obvious why the above doesn't compile, and it's
obvious why your previous reordering threw an exception.
I might order the LINQ book (the 1000 pager you recently reviewed)
since LINQ appears more difficult than I thought.

I haven't reviewed any 1000 page books yet.

LINQ to Objects isn't particularly difficult, but you need to have a
firm grasp of the basics (like extension methods) otherwise you'll come
up with code like the above and not understand why it doesn't compile.
 
R

raylopez99

It's unclear what you're trying to do. Breaking up the query is easy,
but not like that - and just experimenting haphazardly isn't going to
help you. However, I see that once more you've retreated into ad
hominem attacks.


Never know what? It's obvious why the above doesn't compile, and it's
obvious why your previous reordering threw an exception.

I know it's obvious why it DOESN'T work, but the question was: (1) is
it easy to make it work with a one line change? if not, then your
reluctance to provide a short answer is understandable; but, if so,
then (2) it follows you must be incompetent or obstinant.
I haven't reviewed any 1000 page books yet.

Pro LINQ: Language Integrated Query in C# 2008 (Windows.Net)
(Paperback) - 600 pages (rounds to 1000).
LINQ to Objects isn't particularly difficult, but you need to have a
firm grasp of the basics (like extension methods) otherwise you'll come
up with code like the above and not understand why it doesn't compile.

I understand extension methods. It's code that has a .dot in front of
it, that you can customize, like .ToPrint(). It's not considered good
form, unless absolutely necessary.

"Thanks" for your "help". I didn't mean to attack you personally.
Yes I did.

Bye,

RL
 

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