hacker101
hacker101

Reputation: 35

How to access a nested hashtable value in C#

I have a C# program where I need to lookup data based on keys. I am porting my Python code to C# and finding it difficult to implement the equivalent of nested Python dictionaries. After many attempts at using C# Dictionaries, I settled on Hashtable because it is loosely typed.

I am able to write to my nested Hashtable structure, and I can read from it if I iterate. But what I want to do is access specific data based on specific keys.

Here is the code I am using, which works:

        foreach (DictionaryEntry x in ParameterTypes)
        {
            Console.WriteLine(x.Key + " -- ");
            foreach (DictionaryEntry y in x.Value as Hashtable)
            {
                Console.WriteLine(y.Key + ": " + y.Value);
            }
            Console.WriteLine("\n");
        }

It gives me this output (sample):

EVENT_PARAM_SCTP_SHUTDOWN_RESULT --
name: EVENT_PARAM_SCTP_SHUTDOWN_RESULT
usevalid: Yes
description: The results of a SCTP Shutdown
numberofbytes: 1
type: ENUM

EVENT_PARAM_ENBS1APID --
name: EVENT_PARAM_ENBS1APID
numberofbytes: 3
usevalid: Yes
description: eNB S1 AP ID
resolution: 1
type: UINT

However, this code below doesn't work:

Console.WriteLine(ParameterTypes["EVENT_PARAM_ENBS1APID"]["description"]);

What is the proper way to get data based on the key and nested key as I am attempting?

Upvotes: 0

Views: 2318

Answers (3)

Paul Kienitz
Paul Kienitz

Reputation: 878

I agree with the other responders that you should rethink this structure instead of trying to mimic PHP. But if you want to stick with it, the reason your double indexing didn't work is because ParameterTypes["EVENT_PARAM_ENBS1APID"] returns an object, which has no [] operator. You have to cast it as a Hashtable to index it again.

First of all, you'll probably want to use the is operator to determine whether a given node is indeed a nested hashtable. If it is, you can go

((Hashtable) ParameterTypes["EVENT_PARAM_ENBS1APID"])["description"]

or

(ParameterTypes["EVENT_PARAM_ENBS1APID"] as Hashtable)["description"]

Upvotes: 2

ghaberek
ghaberek

Reputation: 267

This code produces the output you seem to expect...

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

namespace TestProject
{
    /// <summary>
    /// Parameter entry for ParameterTypes collection.
    /// </summary>
    class ParameterEntry : Dictionary<string, object>
    {
        // this is just an subclassed Dictionary class
    }

    /// <summary>
    /// Parameter types collection.
    /// </summary>
    class ParameterTypes : Dictionary<string, ParameterEntry>
    {
        // this class is a Dictionary that holds ParameterEntry objects

        /// <summary>
        /// Add the specified value using its name as the key.
        /// </summary>
        /// <param name='value'>
        /// A parameter entry.
        /// </param>
        public void Add(ParameterEntry value)
        {
            string key = (string)value["name"];
            this.Add(key, value);
        }
    }

    class TestProject
    {
        public static void Main (string[] args)
        {
            var entry1 = new ParameterEntry();
            entry1.Add("name", "EVENT_PARAM_SCTP_SHUTDOWN_RESULT");
            entry1.Add("usevalid", "Yes");
            entry1.Add("description", "The results of a SCTP Shutdown");
            entry1.Add("numberofbytes", 1);
            entry1.Add("type", "ENUM");

            var entry2 = new ParameterEntry();
            entry2.Add("name", "EVENT_PARAM_ENBS1APID");
            entry2.Add("numberofbytes", 3);
            entry2.Add("usevalid", "Yes");
            entry2.Add("description", "eNB S1 AP ID");
            entry2.Add("resolution", 1);
            entry2.Add("type", "UINT");

            var types = new ParameterTypes();
            types.Add(entry1);
            types.Add(entry2);

            Console.WriteLine(types["EVENT_PARAM_ENBS1APID"]["name"]);
            Console.WriteLine(types["EVENT_PARAM_ENBS1APID"]["numberofbytes"]);
            Console.WriteLine(types["EVENT_PARAM_ENBS1APID"]["usevalid"]);
            Console.WriteLine(types["EVENT_PARAM_ENBS1APID"]["description"]);
        }
    }
}

You can certainly nest a Dictionary within a Dictionary and you can use strings as the primary keys and nested keys and use an object as the final nested value. You can also subclass the typed Dictionary<> class as your own class to abstract the implementation and make the code easier to read and understand. Keep in mind that if you're coming from Python or any other loosely-typed language, you have to re-think how you're approaching the problem in terms of a strongly-typed language like C#.

Upvotes: 0

Miyuru Ratnayake
Miyuru Ratnayake

Reputation: 456

Try to use generic Dictionary type Dictionary so you can store nested collections:

      Dictionary<string,object> ParameterTypes  = new Dictionary<string,object>();
    //Populate the parameterTypes here
     foreach (var x in ParameterTypes)
    {
        Console.WriteLine(x.Key + " -- ");
        foreach (var in x.Value)
        {
            Console.WriteLine(y.Key + ": " + y.Value);
        }
        Console.WriteLine("\n");
    }

If you have already defined a Class you can use it for the value:

 Dictionary<string, Dictionary<string,YourType>> or similar

Upvotes: 1

Related Questions