469,950 Members | 1,391 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,950 developers. It's quick & easy.

Implicit unsafe casting in foreach? What gives?

Hey Guys,

Would anyone mind explaining why a foreach will implicitly do unsafe
casts, and if there is a way to turn this off?

Here is an example:

ulong[] vals = new ulong[] { ulong.MaxValue };
foreach (uint x in vals)
Console.WriteLine(x);

Thanks,
James

May 14 '07 #1
5 2532
James,

Unfortunately, no. From the language specification:

The type of the expression of a foreach statement must be a collection type
(as defined below), and an explicit conversion (?6.2) must exist from the
element type of the collection to the type of the iteration variable. If
expression has the value null, a System.NullReferenceException is thrown.

Since an explicit conversion exists between ulong and uint, the compiler
is right in this case.

You can get around it yourself, though, by iterating through the
elements manually, and then performing the check of the returned type vs the
type you wish to use.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"james" <ja********@gmail.comwrote in message
news:11**********************@h2g2000hsg.googlegro ups.com...
Hey Guys,

Would anyone mind explaining why a foreach will implicitly do unsafe
casts, and if there is a way to turn this off?

Here is an example:

ulong[] vals = new ulong[] { ulong.MaxValue };
foreach (uint x in vals)
Console.WriteLine(x);

Thanks,
James

May 14 '07 #2
"james" <ja********@gmail.comwrote in message
news:11**********************@h2g2000hsg.googlegro ups.com...
Would anyone mind explaining why a foreach will implicitly do unsafe
casts, and if there is a way to turn this off?

Here is an example:

ulong[] vals = new ulong[] { ulong.MaxValue };
foreach (uint x in vals)
Console.WriteLine(x);
The reason why the foreach does an unsafe cast, is because it doesn't
know otherwise. A foreach can be done on any object that implements
IEnumerable, and IEnumerable returns a GetEnumerator which provides an
IEnumerator which has a method "Current" that returns Object. Therefore,
foreach always thinks that it is dealing with Object, so it always has to do
an unsafe cast regardless of the type of variable that you use to control
the loop. That is, the compiler translates the previous foreach to something
similar to the following:

IEnumerator e = vals.GetEnumerator();
while (e.MoveNext())
{
object obj = e.Current();
uint x= (uint) obj;
Console.WriteLine(x);
}

There is an IEnumerable<Tthat solves the preceding problem. However,
the documentation of System.Array only shows arrays to implement
IEnumerable, and not IEnumerable<typeoftheelements>.


May 14 '07 #3


Tyepd arrays do actually implement IEnumerable<T>. I'm not sure how
to prove this with the documentation, object browser, or Reflector,
but the following code demonstrates it:

private static void Test<T>(IEnumerable<TthingToEnumerate)
{
int[] ints = null;
Test(ints); // works

Array array = null;
Test(array); // doesn't work
}

Also technically a collection does not need to implement IEnumerable
to work with foreach--it only needs a GetEnumerator() method. It's
technically possible to write a class that has GetEnumerator() and
doesn't implement IEnumerable and it will still work with
foreach--although you never want to, just a silly little technicality.

Sam

------------------------------------------------------------
We're hiring! B-Line Medical is seeking .NET
Developers for exciting positions in medical product
development in MD/DC. Work with a variety of technologies
in a relaxed team environment. See ads on Dice.com.

On Mon, 14 May 2007 18:50:42 +0200, "Alberto Poblacion"
<ea******************************@poblacion.orgwro te:
>
The reason why the foreach does an unsafe cast, is because it doesn't
know otherwise. A foreach can be done on any object that implements
IEnumerable, and IEnumerable returns a GetEnumerator which provides an
IEnumerator which has a method "Current" that returns Object. Therefore,
foreach always thinks that it is dealing with Object, so it always has to do
an unsafe cast regardless of the type of variable that you use to control
the loop. That is, the compiler translates the previous foreach to something
similar to the following:

IEnumerator e = vals.GetEnumerator();
while (e.MoveNext())
{
object obj = e.Current();
uint x= (uint) obj;
Console.WriteLine(x);
}

There is an IEnumerable<Tthat solves the preceding problem. However,
the documentation of System.Array only shows arrays to implement
IEnumerable, and not IEnumerable<typeoftheelements>.
May 14 '07 #4
Alberto Poblacion <ea******************************@poblacion.org>
wrote:

<snip>
The reason why the foreach does an unsafe cast, is because it doesn't
know otherwise. A foreach can be done on any object that implements
IEnumerable, and IEnumerable returns a GetEnumerator which provides an
IEnumerator which has a method "Current" that returns Object. Therefore,
foreach always thinks that it is dealing with Object, so it always has to do
an unsafe cast regardless of the type of variable that you use to control
the loop.
That's not quite true. This doesn't compile, for instance:

using System;

class Test
{
static void Main()
{
int[] array = new int[10];
foreach (string x in array)
{
Console.WriteLine (x);
}
}
}

and using generics, things get better even for collections:

using System;
using System.Collections.Generic;
using System.IO;

class Test
{
static void Main()
{
List<Streamlist = new List<Stream>();
foreach (string x in list)
{
Console.WriteLine (x);
}
}
}

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
May 14 '07 #5
"Samuel R. Neff" <sa********@nomail.comschrieb im Newsbeitrag
news:fe********************************@4ax.com...
>

Tyepd arrays do actually implement IEnumerable<T>. I'm not sure how
to prove this with the documentation,
citation from the specs (C#2.0 ECMA):
A one-dimensional array S[] implements the interface
System.Collections.Generic.IList<S>
(IList<Sfor short) and its base interfaces.

The spec of C#1.0 shall have an analog sentence without generics.

Christof
May 15 '07 #6

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by Simon Ford | last post: by
9 posts views Thread by Simon | last post: by
8 posts views Thread by Roger Leigh | last post: by
11 posts views Thread by Steve Gough | last post: by
9 posts views Thread by Kurt | last post: by
6 posts views Thread by Gecko | last post: by
36 posts views Thread by Chad Z. Hower aka Kudzu | last post: by
10 posts views Thread by Pieter Breed | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.