A quick guide for regexes in .NET is available here:
https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference
Access regex matches is done via groups and captures.
Example of extension method for access of all capture values inside matches below.
public static class MatchCollectionExtensions{
public static IEnumerable<string> GetCapturedValues(this MatchCollection matches){
foreach (Match match in matches){
foreach (Group group in match.Groups){
foreach (Capture capture in group.Captures){
yield return capture?.Value;
}
}
}
}
}
Also, using Linqpad is a great resource for learning stuff in C#.
Using the Dump method will show the structure of objects.
Example from the question sample code below.
string page = """
<td><a href="/path/to/file">Name of File</a></td>
""";
Regex qariRegex = new Regex("<td><a href=\"(?<link>.*?)\">(?<name>.*?)</a></td>");
MatchCollection mc = qariRegex.Matches(page);
CaptureCollection cc = mc[0].Captures;
mc.Dump();
//mc[0].Groups[1].Captures[0].Value.Dump();
//mc[0].Groups[2].Captures[0].Value.Dump();
foreach (var element in mc.GetCapturedValues())
{
Console.WriteLine(element);
}

Output of your regex using extension method gave the following result after iterating and running Console.WriteLine :
<td><a href="/path/to/file">Name of File</a></td>
/path/to/file
Name of File
Adjusting the extension method to instead build a Dictionary of Group name as key and capture values inside should be fairly straightforward, for example creating a key in Dictionary concatenating Group name with capture index and then using capture value as the value of dictionary entry.
<>will break it. You can use(?'link'.*)instead in this case. Not entirely relevant to this question but I landed here from a Google search of ".net named capture groups" so I'm sure other people are as well...<>will not break it. I was able to use themyRegex.GetGroupNames()collection as the XML element names.