Skip to content

Variables display isn't showing contents for generic-based dictionaries #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
rkeithhill opened this issue Dec 13, 2015 · 4 comments
Closed

Comments

@rkeithhill
Copy link
Contributor

Specifically the $PSBoundParameters variable in Local scope of a function that specifies parameters. I've modified the code in VariableDetails.GetChildren like so:

else if (dictionary != null)
{
    var res1 = dictionary.OfType<object>().ToList();
    var res2 = dictionary.OfType<KeyValuePair<string,object>>().ToList();
    foreach (var item in dictionary)
    {
        if (item.GetType() != typeof(DictionaryEntry))
        {
            break;
        }

        var entry = (DictionaryEntry)item;
        childVariables.Add(
            new VariableDetails(
                entry.Key.ToString(),
                entry.Value));
    }
    //childVariables.AddRange(
    //    dictionary
    //        .OfType<DictionaryEntry>()
    //        .Select(e => new VariableDetails(e.Key.ToString(), e.Value)));
}

The commented out code at the bottom is the original code. The LINQ operator OfType returns nothing for PSBoundParametersDictionary because it derives from the generic type Dictionary<string, object>. I can see in res1 that the type of object enumerated using the OfType<> method is KeyValuePair<string,object>. However, if I just do the enumeration via a foreach loop, the item type works out to DictionaryEntry even for PSBoundParametersDictionary.

It is late and I'm not quite grokking how this is working and what the best way is to handle both IDictionary and IDictionary<TKey,TValue>. If anybody has any suggestions, let me know. At the very least, the code above (sans the res1/res2 experiment) is better than what we have right now.

@daviwil
Copy link
Contributor

daviwil commented Dec 13, 2015

That is... weird. There seems to be some implicit coercion going on when using the foreach approach. I'm fine with doing it this way though! I'd leave a comment above the loop explaining why it needs to remain a loop so that nobody changes it :)

@rkeithhill
Copy link
Contributor Author

OK I “think” I know the “why” now after spending some time in dotPeek.

Here are the two ways to get an enumerator from a Dictionary<TKey,TValue) based object, that the GetChildren() method has tried:

IDictionaryEnumerator IDictionary.GetEnumerator() 
{
    return new Enumerator(this, Enumerator.DictEntry);
}

IEnumerator IEnumerable.GetEnumerator() 
{
    return new Enumerator(this, Enumerator.KeyValuePair);
}

I believe the foreach construct in C# is using the first one. After all the dictionary variable it iterates over is of type IDictionary. Note that it specifies to output DictEntry objects. The LINQ OfType<T> extension method is using the second which specifies KeyValuePair as the output. This makes sense because OfType<T> operates on objects that are IEnumerable i.e. OfType<T> reinterprets the dictionary variable an IEnumerable.

This gives me confidence that any type that derives from Dictionary<,> will work with the planned change. Ditto for types that implement IDictionary<,> as that interface requires implementation of IEnumerable as well.

@daviwil
Copy link
Contributor

daviwil commented Dec 13, 2015

Sounds good to me, thanks for looking into this!

@rkeithhill
Copy link
Contributor Author

OK getting reading to submit a PR for this with some nice enhancements for the display of collections, dictionaries and value types like DateTime, TimeSpan, etc.
vscodedictionaryvariables

rkeithhill added a commit to rkeithhill/PowerShellEditorServices that referenced this issue Dec 14, 2015
…ing for generic dictionaries like PSBoundParametersDictionary. Also enhanced the determination of what is expandable. We were not allowing structs like DateTime, TimeSpan and DictionaryEntry to expand. Changed test from !IsValueType to !IsPrimitive. Also enhanced the display of property values where we encounter an exception when trying to retrieve the property. Following VS debugger's lead on this on. You can see the display by looking at $Host.Runspace. And we also weren't displaying .NET properties for colletions and dictionaries. We now do that - in addition to the elements in the collection or dictionary. Also, don't try to add properties that are indexers.
daviwil added a commit that referenced this issue Dec 14, 2015
…-bug

For for issue #75, variables display isn't displaying anything for ge…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants