Search code examples
c#linq.net-4.5anonymous-types

LINQ anonymous object is inaccessible due to its protection level


I have LINQ logic that collects regex parsed data into a dynamically-created dictionary. The issue I am facing is accessing the data in the dictionary (Info).

Regex
    .Matches(text, pattern,
        RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture) 
    .OfType<Match>()    
    .Select(mt => new
    {
        Info = mt.Groups["ADKey"].Captures
            .OfType<Capture>()
            .Select(cp => cp.Value)
            .Zip(mt.Groups["ADValue"].Captures.OfType<Capture>().Select(cp => cp.Value),
                (k, v) => new { key = k, value = v })
            .ToDictionary(cp => cp.key, cp => cp.value),
        Nodes = mt.Groups["Key"].Captures
            .OfType<Capture>()
            .Select(cp => cp.Value)
            .Zip(mt.Groups["Value"].Captures.OfType<Capture>().Select(cp => cp.Value),
                (k, v) => new { key = k, value = v })
            .ToDictionary(cp => cp.key, cp => cp.value),
    });

List<string> myInfo = new List<string>();
myInfo = Info.Keys.ToList();

When I try to access the dictionary(info), while converting to list, I get the error that "Info" is inaccessible due to its protection level. How do I fix that?


Solution

  • You are currently creating a list of anonymous types which have a single property, Info, that is a Dictionary<string, string>. You don't appear to be capturing the result in a variable. Then you try to access Info as if it were a single object outside of the RegEx query. Those two Info reference different things.

    The first suggestion I have for you is to change your code like this:

    IEnumerable<Dictionary<string, string>> query =
        Regex
            .Matches(
                text,
                pattern,
                RegexOptions.IgnorePatternWhitespace
                    | RegexOptions.ExplicitCapture) 
            .OfType<Match>()
            .Select(mt => mt.Groups["Key"].Captures
                    .OfType<Capture>()
                    .Select(cp => cp.Value)
                    .Zip(
                        mt.Groups["Value"].Captures
                            .OfType<Capture>()
                            .Select(cp => cp.Value),
                        (k, v) => new
                        {
                            key = k,
                            value = v
                        })
                    .ToDictionary(cp => cp.key, cp => cp.value));
    

    Now, I don't believe you want a IEnumerable<Dictionary<string, string>>, because on your next two lines you seem to want the to pull the keys straight out of the results.

    It appears that you might want this:

    Dictionary<string, string> query =
        Regex
            .Matches(text, pattern,
                RegexOptions.IgnorePatternWhitespace
                    | RegexOptions.ExplicitCapture) 
            .OfType<Match>()
            .SelectMany(mt => mt.Groups["Key"].Captures
                .OfType<Capture>()
                .Select(cp => cp.Value)
                .Zip(
                    mt.Groups["Value"].Captures
                        .OfType<Capture>()
                        .Select(cp => cp.Value),
                    (k, v) => new
                    {
                        key = k,
                        value = v
                    }))
            .ToDictionary(cp => cp.key, cp => cp.value);
    

    But I suspect this will have key collisions.

    I think you probably want something like this:

    Match match = Regex.Match(text, pattern,
        RegexOptions.IgnorePatternWhitespace
            | RegexOptions.ExplicitCapture);
    
    Dictionary<string, string> result =
        match
            .Groups["Key"]
            .Captures
            .OfType<Capture>()
            .Select(cp => cp.Value)
            .Zip(
                match.Groups["Value"].Captures
                    .OfType<Capture>()
                    .Select(cp => cp.Value),
                (k, v) => new
                {
                    key = k,
                    value = v
                })
            .ToDictionary(cp => cp.key, cp => cp.value);
    

    Then you can do this:

        List<string> myInfo = result.Keys.ToList();
    

    Given your updated question it seems to me you might want this:

    Match match =
        Regex.Match(text, pattern,
            RegexOptions.IgnorePatternWhitespace
                | RegexOptions.ExplicitCapture);
    
    var result = new
    {
        Info = match.Groups["ADKey"].Captures
            .OfType<Capture>()
            .Select(cp => cp.Value)
            .Zip(match.Groups["ADValue"].Captures.OfType<Capture>().Select(cp => cp.Value),
                (k, v) => new { key = k, value = v })
            .ToDictionary(cp => cp.key, cp => cp.value),
        Nodes = match.Groups["Key"].Captures
            .OfType<Capture>()
            .Select(cp => cp.Value)
            .Zip(match.Groups["Value"].Captures.OfType<Capture>().Select(cp => cp.Value),
                (k, v) => new { key = k, value = v })
            .ToDictionary(cp => cp.key, cp => cp.value),
    };
    
    List<string> myInfo = result.Info.Keys.ToList();