Néo
Néo

Reputation: 23

Create dictionary with dynamic keys in C#

When programming with C/C++ I sometimes used to have a dictionary with references to functions according to the specified keys. However, I don't really know how to have something similar in C# allowing me dynamic keys.

I'm working on Unity and I'd like for exemple to invoke a function when I press left mouse click on my Unity project, is it possible ?

I'd really appreciate every comments on this.

Upvotes: 2

Views: 7102

Answers (3)

Programmer
Programmer

Reputation: 125435

You can use Dictionary<KeyCode, System.Action> signature to accomplish that. Get all the code codes and store them into an array with System.Enum.GetValues(typeof(KeyCode));. You can then pair your keys with your functions with keyCodeToFuncDic.Add(KeyCode.YourKeyCode, YourFunction);

In the Update function, use for loop to loop over the KeyCodes stored in the beginning. Check if any of those keys is pressed. If pressed, check if it is in the Dictionary. If the that KeyCode exist in the dictionary, use the pressed key to Invoke the function in the Dictionary value, which will eventually call the function that is stored in the Dictionary.

Code:

Dictionary<KeyCode, System.Action> keyCodeToFuncDic = new Dictionary<KeyCode, System.Action>();
Array allKeyCodes;

void Start()
{
    //Get all codecodes
    allKeyCodes = System.Enum.GetValues(typeof(KeyCode));

    //Register Keycodes to functios
    keyCodeToFuncDic.Add(KeyCode.Mouse0, myFunction); //Left mouse
    keyCodeToFuncDic.Add(KeyCode.Mouse1, myFunction2); //Right mouse
}

void myFunction()
{
    Debug.Log("Left Mouse Clicked");
}

void myFunction2()
{
    Debug.Log("Right Mouse Clicked");
}

void Update()
{
    foreach (KeyCode tempKey in allKeyCodes)
    {
        //Check if any key is pressed
        if (Input.GetKeyDown(tempKey))
        {
            //Check if the key pressed exist in the dictionary key
            if (keyCodeToFuncDic.ContainsKey(tempKey))
            {
                //Debug.Log("Pressed" + tempKey);

                //Call the function stored in the Dictionary's value
                keyCodeToFuncDic[tempKey].Invoke();
            }
        }
    }
}

Upvotes: 1

Mihail Shishkov
Mihail Shishkov

Reputation: 15847

When I see "dynamic keys" I think for something else like having a dynamic type be the key for the dictionary. However what you need can be easily achieved. In C# "pointers to functions" are called delegates (but way better than C pointers to functions) thus you need a dictionary that has the char type as the key and one of those delegates as the value. In .net framework 4.0 and above there are predefined generic delegates called Func<T...> and Action<T...>. Basically if you want your function to return a value you will use Func and the Action will be used in the place of a void method.

So you can have something like this:

var keyMap = new Dictionary<char, Func<string, bool>>()
{
    {'w', MoveUp},
    {'s', MoveDown},
    {'a', s => true}, // using lambda expression
    {
        'd', delegate(string s)
        {
            if (string.IsNullOrWhiteSpace(s) == false)
            {
                //
            }
            return true;
        }
    } // using anonymous method
};

// then you can call those like this
var allow = keyMap['w']("some input");
if (allow)
{
    // .... 
}

public bool MoveUp(string input)
{
    return true;
}

public bool MoveDown(string input)
{
    return true;
}

Here are the docs https://msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx

Upvotes: 1

Imran Sh
Imran Sh

Reputation: 1774

I think you can use this: First define a Delegate for your task (Jobs assigned to keys press in your example):

public delegate void MyJob();

Then define your dictionary:

Dictionary<string, MyJob> myBinding = new Dictionary<string, MyJob>()
{
    { "left", delegate() { Console.WriteLine("Left Key pressed"); } },
    { "right", delegate() { Console.WriteLine("Right Key pressed"); } },
    { "up", delegate() { Console.WriteLine("Up Key pressed"); } },
    { "down", delegate() { Console.WriteLine("Down Key pressed"); } }
};

And finally use it:

public void Mapper(string pressedKey)
{
    myBinding[pressedKey]();
}

I hope this help you to solve your problem. If you need to more detail let me know.

Upvotes: 4

Related Questions