-
-
- (1861)
-
premium membership
-
Posts
180
|
SignedInGamerCollection indexing oddness
|
I've looked through a few posts about SignedInGamerCollection now but I'm still confused about something odd that I'm seeing. As Shawn points out in this thread ( http://forums.xna.com/forums/p/27816/153775.aspx) a SignedInGamerCollection has two indexer overloads. The int indexer removes the null entries so index 0 should give you the first signed in gamer even if they're using pad 3 whereas PlayerIndex.One gives you whoever is on the first pad regardless and hence may be null.
However, I've currently got my CG profile signed in on pad 2, pad 1 is switched off and I'm running these lines of code:
| int i = 0; |
| SignedInGamer gamera = gamers[0]; |
| SignedInGamer gamerb = gamers[i]; |
| SignedInGamer gamerc = gamers[PlayerIndex.One]; |
| SignedInGamer gamerd = gamers[PlayerIndex.Two]; |
gamerb, gamerc and gamerd come out as expected, gamerc is null but gamerb and gamerd point to my SmudgedCat profile. gamera, however, comes out as null! I would have thought there wasn't any way that gamers[0] and gamers[i] could go through different indexers as they are both Int32's,... aren't they? Curiously gamers[1] gives me an ArgumentOutOfRangeException implying that it isn't somehow accidentally calling the PlayerIndex indexer.
I'm confused!,
Dave
|
|
-
-
- (12845)
-
Team XNA
-
Posts
8,526
|
Re: SignedInGamerCollection indexing oddness
|
That's crazy. Wild guess: could the C# compiler be somehow interpreting the constant 0 as a PlayerIndex value rather than an integer? The symbol '0' is magic in C#: this can represent any type of integer, or float, or enum. I would have thought the integer interpretation would have priority, but maybe that's not how it works?
Try using gamers[(int)0] and see if that gives the same result...
XNA Framework Developer -
blog - homepage
|
|
-
-
- (4224)
-
premium membership
-
Posts
1,611
|
Re: SignedInGamerCollection indexing oddness
|
I have confirmed this to be 100% true with a test application. I created a collection that overloads indexing to support PlayerIndex as the index, and the compiler does in fact convert a literal 0 to PlayerIndex.One and call the PlayerIndex version of the the get_Item property.
I guess it is looking up the class tree from the bottom up, trying to find the first get_Item for which it can implicitly convert the 0 literal to the target index type. It finds the PlayerIndex one first, and uses that (but only for zero, not 1, 2, or 3)? Crazy indeed.
public class FooCollection : List<string>
{
public string this[PlayerIndex index]
{
get
{
return null; // set breakpoint here
}
}
}
FooCollection collection = new FooCollection();
collection.Add("One");
collection.Add("Two");
int i = 0;
string a = collection[i]; // calls the int index property
string b = collection[0]; // calls the PlayerIndex version always
string c = collection[2]; // calls the int index property
I would file it on connect, but it is definitely not a XNA issue. Casting the 0 index call to an int (i.e. string b = collection[(int)0]) does not change anything. The real question is, could this be causing issues somewhere else where this implicit conversion causes the wrong method call?
|
|
-
-
- (1861)
-
premium membership
-
Posts
180
|
Re: SignedInGamerCollection indexing oddness
|
It feels like it must be using the PlayerIndex indexer somehow. I didn't realise '0' had some odd attributes which would explain why gamers[1] seems to be correct. Having tested it though, even gamers[(int)0] gives the same result!
Cheers,
Dave
|
|
-
-
- (1861)
-
premium membership
-
Posts
180
|
Re: SignedInGamerCollection indexing oddness
|
|
|
-
-
- (20326)
-
premium membership
MVP
-
Posts
12,380
|
Re: SignedInGamerCollection indexing oddness
|
Its unlikley to be a bug... there's about 4 pages in the c# spec called overload resolution that describes in horrible detail how the compiler decides to resolve an ambiguous overload. So horrible that I have never been able to understand it fully. Page 161 onward if you want to try http://www.ecma-international.org/publications/standards/Ecma-334.htm
Even if it was there is no way around the 7 day rule. Especially since you could have actually tested for this issue before you submitted it even if its a confusing resolution.
Play Kissy Poo - a game for 4 year olds on Xbox and windows The ZBuffer News and information for XNA Follow The Zman on twitter, Email me Please read the forum FAQs - Bug/Feature reporting Don't forget to mark good answers and good playtest feedback when you see it!!!
|
|
-
-
- (4224)
-
premium membership
-
Posts
1,611
|
Re: SignedInGamerCollection indexing oddness
|
It may not be a compiler bug, but it is misleading. It only occurs when you have two index properties defined across more than one class in a hierarchy. Below is a sample console application.
| using System; |
| |
| namespace ZeroConversionIssue |
| { |
| class Program |
| { |
| public enum PlayerIndex |
| { |
| One, |
| Two, |
| Three, |
| Four |
| } |
| |
| static void Main(string[] args) |
| { |
| int zero = 0; |
| |
| Console.Out.WriteLine("Indexers in same class"); |
| Console.Out.WriteLine("----------------------"); |
| |
| GoodCollection good = new GoodCollection(); |
| Console.Out.WriteLine(good[0]); |
| Console.Out.WriteLine(good[zero]); |
| Console.Out.WriteLine(good[PlayerIndex.One]); |
| Console.Out.WriteLine(good[1]); |
| |
| Console.Out.WriteLine(); |
| Console.Out.WriteLine("Indexers in ancestor class"); |
| Console.Out.WriteLine("--------------------------"); |
| |
| BadCollection bad = new BadCollection(); |
| Console.Out.WriteLine(bad[0]); |
| Console.Out.WriteLine(bad[zero]); |
| Console.Out.WriteLine(bad[PlayerIndex.One]); |
| Console.Out.WriteLine(bad[1]); |
| |
| Console.Read(); |
| } |
| |
| public class GoodCollection |
| { |
| public string this[int index] |
| { |
| get { return "by index " + index; } |
| } |
| |
| public string this[PlayerIndex playerIndex] |
| { |
| get { return "by PlayerIndex " + playerIndex; } |
| } |
| } |
| |
| public abstract class BadCollectionBase |
| { |
| public string this[int index] |
| { |
| get { return "by index " + index; } |
| } |
| } |
| |
| public class BadCollection : BadCollectionBase |
| { |
| public string this[PlayerIndex playerIndex] |
| { |
| get { return "by PlayerIndex " + playerIndex; } |
| } |
| } |
| } |
| } |
| |
This should (logically) output the same for the version with indexers in the same class as the version where it splits, specifically:
Indexers in same class
----------------------
by index 0
by index 0
by PlayerIndex One
by index 1
Indexers in ancestor class
--------------------------
by index 0
by index 0
by PlayerIndex One
by index 1
But it instead outputs:
Indexers in same class
----------------------
by index 0
by index 0
by PlayerIndex One
by index 1
Indexers in ancestor class
--------------------------
by PlayerIndex One
by index 0
by PlayerIndex One
by index 1
Since the SignedInGamerCollection contains the PlayerIndex indexer and it's base class contains the integer version, it is resolving the lower PlayerIndex version first and implicitly converting zero to PlayerIndex.One. Anyone expecting it to return the first signed in gamer is SOL, and searching the forums shows a couple of people who have been hit by this. I'm not sure what the fix would be, as it may be to specification.
Interesting, nontheless.
|
|
-
-
- (64)
-
premium membership
Team XNA
-
Posts
563
|
Re: SignedInGamerCollection indexing oddness
|
dadoo, my friend, you may very well have found a C# compiler bug!
I reviewed the C# 3.0 language specification:
http://msdn.microsoft.com/en-us/vcsharp/aa336809.aspx
Here's what I found:
Section 7.5.6.2, "Indexer access", indicates that this scenerio should perform a member look up for the indexer which returns a method group. The inheritance hierarchy should have no affect on the set of methods contained in this group.
Section 7.4.3.2, "Better function member", does not indicate a that the inheritance hierarchy has an effect on the method preference order. The behavior should be consistent.
So it appears that this behavior is in fact a bug!
One other thing to note is that section 6.1.3, "Implicit enumeration conversions", does not specify the conversion priorities for enums vs numeric types. This might be specified somewhere else in the document, but could also very well be an under-specification bug.
I will forward this thread to the C# compiler PM. Thanks!
Brandon Bloom Software Design Engineer XNA Platform and Tools
|
|
-
-
- (4224)
-
premium membership
-
Posts
1,611
|
Re: SignedInGamerCollection indexing oddness
|
Brandon Bloom:dadoo, my friend, you may very well have found a C# compiler bug!
I'm pretty sure that anyone who has called Gamer.SignedInGamers[0] while using controller #2 and got a NULL exception found it first :)
Just to clarify for anyone who finds this thread, the only way to get the first signed in gamer from a SignedInGamerCollection at the moment is to do:
int index = 0;
SignedInGamer gamer = Gamer.SignedInGamers[index];
instead of the expected
SignedInGamer gamer = Gamer.SignedInGamers[0];
|
|
-
-
- (15036)
-
premium membership
MVP
-
Posts
8,408
|
Re: SignedInGamerCollection indexing oddness
|
I popped this into the wiki so we'll be able to refer to it easier the next 27 times it comes up. :)
Jim Perry - Microsoft XNA MVP If people spent a minute searching the forums and reading the FAQs before posting I'd be out of a job. Got some XNA Game Studio/XNA Framework development info to share with the community? Put it on the XNA Wiki. Please mark posts as Answers or Good Feedback when appropriate.
|
|
|