Home > Mobile >  Split an Iterator containing two foreach loops in two different functions
Split an Iterator containing two foreach loops in two different functions

Time:11-04

I have the current function:

private IEnumerable<string> GetKeysStringValues(RegistryKey key)
{
    foreach (var subKey in GetAllSubKeys(key))
    {
        foreach (var value in subKey.GetValueNames())
        {
            if (subKey.GetValueKind(value) == RegistryValueKind.String)
            {
                yield return (string) subKey.GetValue(value);
            }
        }
    }
}

It:

  1. Parse all subkeys of a registry key
  2. For each subkeys, parse all of its values
  3. If the value is a string, adds it to the iterator

My concern is that there's two embedded for-each loops, which I do not like at all. I'd like to split this function in two.

The problem is that I end up in the end with a return type of IEnumerable<IEnumerable<string>>

I tried to build the Iterator in the second function only, and directly return it in the first, but doing this I miss all the subsequent calls.

This is the code that caused it:

    private IEnumerable<IEnumerable<string>> GetSubKeysStringValues(RegistryKey key)
    {
        IEnumerable<string> enumerable = Enumerable.Empty<string>();
        
        foreach (var subKey in GetAllSubKeys(key))
        {
            yield return GetKeysStringValues(subKey));
        }
    }

    private IEnumerable<string> GetKeysStringValues(RegistryKey key)
    {
        foreach (var value in key.GetValueNames())
        {
            if (key.GetValueKind(value) == RegistryValueKind.String)
            {
                yield return (string) key.GetValue(value);
            }
        }
    }

How would you do that ?

Edit:

I have this solution so far, but could it be improved ?

private IEnumerable<string> GetSubKeysStringValues(RegistryKey key)
{
    IEnumerable<string> enumerable = Enumerable.Empty<string>();
    
    foreach (var subKey in GetAllSubKeys(key))
    {
        enumerable = enumerable.Concat(GetKeysStringValues(subKey));
    }

    return enumerable;
}

private IEnumerable<string> GetKeysStringValues(RegistryKey key)
{
    foreach (var value in key.GetValueNames())
    {
        if (key.GetValueKind(value) == RegistryValueKind.String)
        {
            yield return (string) key.GetValue(value);
        }
    }
}

CodePudding user response:

I have this solution so far, but could it be improved ?

Your solution is fine. If you want more compact code, you can use the LINQ method SelectMany, whose purpose is to "flatten" an IEnumerable<IEnumerable<T>> into an IEnumerable<T>:

private IEnumerable<string> GetSubKeysStringValues(RegistryKey key)
{
    return GetAllSubKeys(key).SelectMany(subKey => GetKeysStringValues(subKey));
}

...or, if you prefer query syntax (yields the same result and probably even the same IL code):

private IEnumerable<string> GetSubKeysStringValues(RegistryKey key)
{
    return from subKey in GetAllSubKeys(key)
           from value in GetKeysStringValues(subKey)
           select value;
}
  • Related