Mapping a user input string to a corresponding block of code My idea is I can define a block of code (inline) that corresponds to an input string then can call that block of code when given that input.

I'm used to this sort of structure in JavaScript like so:

var lookup = {
  "foo": function() { ... },
  "bar": function() { ... },
};

lookup["foo"];


And I'm looking for a C# equivalent. So far I've come up with the following and it seems to work, but I don't know if it could be simplified or improved upon.

class CortanaFunctions
{
        /*
        This is the lookup of VCD CommandNames as defined in 
        CustomVoiceCommandDefinitios.xml to their corresponding actions
        */
        public readonly static Dictionary&lt;string, Delegate&gt; vcdLookup = new Dictionary&lt;string, Delegate&gt;{

            /*
            {&lt;command name from VCD&gt;, (Action)(async () =&gt; {
                 &lt;code that runs when that commmand is called&gt;
            })}
            */

            {"OpenToDoList", (Action)(async () =&gt; {
                StorageFile file = await Package.Current.InstalledLocation.GetFileAsync(@"ToDo.doc");
                await Launcher.LaunchFileAsync(file);
            })},

            {"OpenReddit", (Action)(async () =&gt; { 
                 Uri website = new Uri(@"http://www.reddit.com");
                 await Launcher.LaunchUriAsync(website);
             })},

        };

        /*
        Register Custom Cortana Commands from VCD file
        */
        public static async void RegisterVCD()
        {
            StorageFile vcd = await Package.Current.InstalledLocation.GetFileAsync(
                   @"CustomVoiceCommandDefinitions.xml");
            await VoiceCommandDefinitionManager
                   .InstallCommandDefinitionsFromStorageFileAsync(vcd);
        }

        /*
        Look up the spoken command and execute its corresponding action
        */
        public static void RunCommand(VoiceCommandActivatedEventArgs cmd)
        {
            SpeechRecognitionResult result = cmd.Result;
            string commandName = result.RulePath[0];
            vcdLookup[commandName].DynamicInvoke();
        }

 }


VCD file:



&lt;?xml version="1.0" encoding="utf-8" ?&gt;

&lt;VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.2"&gt;
  &lt;CommandSet xml:lang="en-us" Name="CustomCommands"&gt;
   &lt;CommandPrefix&gt; listen here &lt;/CommandPrefix&gt;
    &lt;Example&gt; open to do list, open reddit&lt;/Example&gt;


    &lt;Command Name="OpenToDoList"&gt;
      &lt;Example&gt; open to do list &lt;/Example&gt;          
      &lt;ListenFor&gt; open to do list&lt;/ListenFor&gt;    
      &lt;Feedback&gt; opening your to do list&lt;/Feedback&gt;
      &lt;Navigate/&gt;          
    &lt;/Command&gt;

    &lt;Command Name="OpenReddit"&gt;
      &lt;Example&gt; open reddit &lt;/Example&gt;          
      &lt;ListenFor&gt; open reddit &lt;/ListenFor&gt;    
      &lt;Feedback&gt; opening reddit &lt;/Feedback&gt;
      &lt;Navigate/&gt;          
    &lt;/Command&gt;
  &lt;/CommandSet&gt;
&lt;/VoiceCommands&gt;
A problem with the code is that the async lambdas in the dictionary are actually async void.


  Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task&lt;T&gt; method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started. -- Async/Await - Best Practices in Asynchronous Programming


It's also confusing because vcdLookup[commandName].DynamicInvoke() looks like a blocking call, but it isn't. Consider this code:

private static readonly Dictionary&lt;string, Delegate&gt; vcdLookup = new Dictionary&lt;string, Delegate&gt;
{
    { "OpenToDoList", (Action)(async () =&gt;
        {
            Console.WriteLine("Opening to-do list...");
            await Task.Delay(TimeSpan.FromSeconds(1));
            Console.WriteLine("Opened to-do list");
        })
    }
};

public static void RunCommand(string command)
{
    vcdLookup[command].DynamicInvoke();
    Console.WriteLine("Finished command");
}


If we call RunCommand("OpenToDoList"), the output is


  Opening to-do list...
  
  Finished command
  
  Opened to-do list


I would recommend instead to change vcdLookup to a Dictionary&lt;string, Func&lt;Task&gt;&gt;.

private static readonly IReadOnlyDictionary&lt;string, Func&lt;Task&gt;&gt; vcdLookup = new Dictionary&lt;string, Func&lt;Task&gt;&gt;
{
    { "OpenToDoList", async () =&gt;
        {
            StorageFile file = await Package.Current.InstalledLocation.GetFileAsync(@"ToDo.doc");
            await Launcher.LaunchFileAsync(file);
        }
    }
};

public static async Task RunCommandAsync(string command)
{
    SpeechRecognitionResult result = command.Result;
    string commandName = result.RulePath[0];
    await vcdLookup[commandName]();
}




A couple of other notes:


Async methods should have the suffix Async, by convention
You probably don't want to make vcdLookup public, exposing it to the world
You can declare vcdLookup as an IReadOnlyDictionary so that its contents are not modified after creation