Iterate through Generic Dictionary?

How does one iterate through a generic dictionary?

I could find example code in C#, but attempting to adapt it to UnityScript hasn't worked - I get the error Cannot convert 'Object' to 'System.Collections.Generic.KeyValuePair'.

#pragma strict    
static function SetActive( inDict : Dictionary.<String,GameObject>, newState : boolean )
    {
    for(var cObj:KeyValuePair.<String,GameObject> in inDict)
        cObj.Value.active = newState;
    }

3 Answers

3

The UnityScript foreach statement is not very helpful when you want to use static typing (which you should, it’s faster) or generics like this. Instead, fall back to this slightly less pretty enumerator-based syntax:

for(var e=inDict.GetEnumerator(); e.MoveNext();)
    e.Current.Value.active = newState;

or for clarity:

var e = inDict.GetEnumerator();
while (e.MoveNext())
    e.Current.Value.active = newState;

Most importantly, this also works with #pragma strict (which helps you ensure you’re writing efficient code), and does not require #pragma downcast.

The basic problem otherwise is that UnityScript’s foreach only works with Object subclasses, whereas DictionatyEntry<K,V> is a value type.

This is definitely a better alternative than the accepted answer! Thanks!

You can also iterate through the keys (or values) of a dictionary, which might simplify the code. The following samples compile, I haven't tried running them.

By key:

static function SetActive( inDict : Dictionary.<String,GameObject>, newState : boolean )
{
    for(var cKey in inDict.Keys)
        inDict[cKey].active = newState;
}

or by value:

static function SetActive( inDict : Dictionary.<String,GameObject>, newState : boolean )
{
    for(var cObj in inDict.Values)
        cObj.active = newState;
}

Awesome! With #pragma strict I found it necessary to change the fourth line to (cObj as GameObject).active = newState;

could you say "for(var cObj:GameObject in iDict.Values)"? (I'm not a javascript guy, so I'm making this up as I go along ...)

Fairly odd, but this fixes it:

class Whatever
{
    static function SetActive( inDict : Dictionary.<String,GameObject>, newState : boolean )
    {
        for(var cObj:KeyValuePair.<String,GameObject> in inDict)
            cObj.Value.active = newState;
    }
}

No clue why right now, but with the implicit class it just dies

Edit:

add in #pragma downcast It'll downcast it to the correct type then. Still no clue why

That does work, but I don't understand why either. I'm wrapping all the scripts in my utilities into a Utilities class, and now I get that DestroyImmediate isn't a member of Object. This is all very strange...

Edited the answer, still no clue but quicker (and more elegant) fix

Oh, the DestroyImmediate one I know. Object in js is mapped to System.Object for some bizarre reason. If you use GameObject.DestroyImmediate, it should fix that

Okay, it seems that if this function is in any class that is called by another class, then I get the "Cannot convert 'Object'..." error.

You'll probably need to use #pragma downcast to those too. This seems like a compiler error to be honest