If you try to compile the query below in Visual Basic .NET, it fails.
From x In {1, 2} Select x.ToString()
The error given by the compiler is:
Range variable name cannot match the name of a member of the 'Object' class.
There is nothing wrong with the equivalent C# query, though:
from x in new[]{1, 2} select x.ToString()
This does not happen with the ToString
overload that takes a format (it is a member of Int32, not Object). It does happen with other members of Object, as long as they don't take an argument: with GetType and GetHashCode it fails; with Equals(object) it compiles.
Why is this restriction in place, and what alternatives can I use?
ToString(Decimal, NumberFormatInfo) Converts a Decimal value to a String value, using the specified number format. ToString(UInt64) Converts a Ulong value to a String value.
ToString returns a string that represents the current object. It is the main formatting method in . NET. The default implementation of the method returns the fully qualified name of the object's type.
I couldn't tell you exacly why VB has this ridiculousness, but the simple workaround is to put the method call in parens.
Dim q = From x In {1, 2} Select (x.ToString())
Here's how I understand it. Consider the following code:
Dim q = From x In {"Bob", "Larry"}
Select x.Length
Select Length * 2
In the query above, the name of the Length
variable is automatically "guessed" for you by the VB compiler based on the expression x.Length
. Now, it's true that you didn't ask for this; it's just a feature that's provided whether you like it or not. But now consider this:
Dim q = From x In {"Bob", "Larry"}
Select (x.Length)
Select Length * 2
The above does not compile because the expression inside the first Select
clause is not as simple as in the first case (believe it or not); the parentheses complicate matters just enough for the compiler not to pick the name Length
; instead, it generates a name that is not usable from code.
So basically what's happening with ToString()
is that this expression is simple enough for the compiler to use to generate a variable name, which could be used if the query were expanded to make use of this variable, e.g.:
Dim q = From x In { 1, 2 }
Select x.ToString()
Select ToString.Length
However, ToString
is not a legal name for a variable since it is a member of System.Object
(why this would be the case for variables within LINQ queries but not for standard local variables, I couldn't say).
While I can't offer details about the error, a simple workaround it:
From x In {1, 2, 3} Let str = x.ToString() Select str
For what it's worth, when you have the following line:
Dim b = From num In {1, 2, 3} Select num.ToString("d")
it is compiles and decompiles to (using Reflector, to C#):
public class Class1
{
[CompilerGenerated]
private static string _Lambda$__1(int num)
{
return num.ToString("d");
}
public void Test1()
{
IEnumerable<string> b = new int[] { 1, 2, 3 }
.Select<int, string>(new Func<int, string>(Class1._Lambda$__1));
}
}
There doesn't seem to be any anonymous class along the way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With