Speeding up thousands of string parses
You should take a look at the possibility to name groups in regex patterns; your match pattern can then be a oneliner:

  const string pattern = @"^(?&lt;name&gt;\w+)\[(?&lt;index&gt;\d+)\]$";

  Match match = Regex.Match(command[2], pattern);

  if (match.Success)
  {
    string featureName = match.Groups["name"].Value;
    int index = int.Parse(match.Groups["index"].Value);

    try
    {
      // TODO: use the information
    }
    catch (Exception ex)
    {
       // TODO: Notify consumer
    }
  }
  else
  {
    // TODO: notify consumer
  }


As shown, the pattern for the index is changed from .*? to \d+ which is more precise and hence more efficient because it doesn't need the non-greedy operator ?.




if (command.Length &lt; 5) //can't be more than 5 parameters
{
    return;
}



When meeting an error you just return from the method without doing anything. Shouldn't you notify the consumer/log the situation/condition?



You don't write from where the command information comes from, but if you read it from a text file, I think I would parse the string information while reading the file and then create a set of command objects defined as something like:

public class CommandInfo
{
  public string Action { get; set; }
  public string Type { get; set; }
  public string ListName { get; set; }
  public int Index { get; set; }
  public Point Vertex { get; set; }
}


Or whatever is suitable for your needs

This may not improve performance but it is more "type safe" than just dispatching an array of strings around.



According to efficiency:

You write, that you have thousands of commands for the same shape, but it seems that you requery a set of shapes inMemoryFeatureLayer.FeatureSource for every command. Whouldn't it be more efficient if you group the commands for each shape, so that you only have to query for the shape once and then can execute all the related commands?



TIP: If you are using Visual Studio 2019, you get help from intellisense and color coding if you compose the regex pattern directly in the call to Match or Matches:

Match match = Regex.Match(command[2], @"^(?&lt;name&gt;\w+)\[(?&lt;index&gt;\d+)\]$");




UPDATE

FYI: there has been some discussion in the comments to various answers about which approach is the most efficient, when extracting the name of the list of vertices and the index from a string like command[2] = "testLine[10]" => "testLine" and 10. So I ran some comparison tests for the following methods:

const string pattern = @"^(?&lt;name&gt;\w+)\[(?&lt;index&gt;\d+)\]$";

Regex regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.Singleline);
void DoRegex()
{
  foreach (string item in data)
  {
    Match match = regex.Match(item);
    if (match.Success)
    {
      string featureName = match.Groups["name"].Value;
      int index = int.Parse(match.Groups["index"].Value);
      testResult += index ^ featureName.GetHashCode();
    }
    else
    {
      throw new InvalidOperationException("DoRegex match");
    }
  }
}

void DoSplitString()
{
  foreach (string item in data)
  {
    string[] split = item.Split('[', ']');
    string featureName = split[0];
    if (int.TryParse(split[1], out int index))
      testResult += index ^ featureName.GetHashCode();
    else
      throw new InvalidOperationException("DoSplitString TryParse");
  }
}

void DoIndexOf()
{
  foreach (string item in data)
  {
    int endIndex = item.IndexOf('[');
    string featureName = item.Substring(0, endIndex);
    if (int.TryParse(item.Substring(endIndex + 1, item.Length - endIndex - 2), out int index))
      testResult += index ^ featureName.GetHashCode(); 
    else
      throw new InvalidOperationException("DoIndexOf TryParse");
  }
}

void DoStringBuilder()
{
  foreach (string item in data)
  {
    string featureName = "";
    int index = 0;
    char stop = '[';

    StringBuilder builder = new StringBuilder();
    foreach (char ch in item)
    {
      if (ch == stop)
      {
        if (stop == '[')
        {
          featureName = builder.ToString();
          stop = ']';
        }
        else
        {
          if (int.TryParse(builder.ToString(), out index))
            testResult += index ^ featureName.GetHashCode();
          else
            throw new InvalidOperationException("DoStringBuilder TryParse");
          break;
        }
        builder.Clear();
      }
      else
      {
        builder.Append(ch);
      }
    }
  }
}


I use a compiled instance for Regex, which reduces the duration for this test with about 600 ms compared to an uncompiled version - when it is compiled once and the same instance is reused for all tests. testResult serves as a simple validation.

The dataset is generated as (the data creation is not part of the measures):

const int testCount = 2000;
const int randSeed = 5;
Random rand = new Random(randSeed);
IList&lt;string&gt; data;
int testResult = 0;

IEnumerable&lt;string&gt; CreateData(int count)
{
  string chars = "abcdefghijklmnopqrstuwxyz";

  for (int i = 0; i &lt; count; i++)
  {
    yield return $"{(string.Join("", Enumerable.Range(1, rand.Next(10, 30)).Select(n =&gt; chars[rand.Next(0, chars.Length)])))}[{rand.Next(0, 100)}]";
  }
}


public void Run()
{
  data = CreateData(1000).ToList();
  ...


I ran each method 2000 times in order to measure some realistic averages with the same dataset with 1000 strings for all measures. The result is rather disappointing for the Regex approach:

testResult: 2052366768
Result for test DoSplitString:
Iterations:                      2000
Average:                      0,34116 Milliseconds
Min:                          0,29660 Milliseconds
Max:                          1,17520 Milliseconds
Total:                      682,31420 Milliseconds


testResult: 2052366768
Result for test DoRegex:
Iterations:                      2000
Average:                      1,69160 Milliseconds
Min:                          1,48380 Milliseconds
Max:                          6,16170 Milliseconds
Total:                     3383,19930 Milliseconds


testResult: 2052366768
Result for test DoIndexOf:
Iterations:                      2000
Average:                      0,22634 Milliseconds
Min:                          0,19200 Milliseconds
Max:                          0,93010 Milliseconds
Total:                      452,68460 Milliseconds

testResult: 2052366768
Result for test DoStringBuilder:
Iterations:                      2000
Average:                      0,36898 Milliseconds
Min:                          0,33100 Milliseconds
Max:                          1,36560 Milliseconds
Total:                      737,96910 Milliseconds


IndexOf is by far the most efficient



As t3chb0t writes in his comments, the regex pattern can be optimized significantly to 

const string pattern = @"^(?&lt;name&gt;.+)\[(?&lt;index&gt;.+)\]$";

static readonly Regex regex = new Regex(pattern, RegexOptions.Compiled);


Running the test with this pattern gives this result:

testResult: 2052366768
Result for test DoRegex:
Iterations:                      2000
Average:                      0,97967 Milliseconds
Truncated Average:            0,97777 Milliseconds
Min:                          0,84020 Milliseconds
Max:                          4,91550 Milliseconds
Total:                     1959,33570 Milliseconds