Is it possible to cache IEnumerable lazy evaluation results?

I am working on a method to find the path to a configuration file. You need to do this in two passes: first find any existing configuration files, then open back and find the first path to write.

Despite the fact that I am too worried about my specific situation, it made me think: is it possible to have both a lazy assessment and prevent multiple transfers?

To illustrate what I mean, consider the following code:

public IEnumerable<string> GetPaths()
{
    Console.WriteLine("GetPaths() Returning 'one'");
    yield return "one";
    Console.WriteLine("GetPaths() Returning 'two'");
    yield return "two";
    Console.WriteLine("GetPaths() Returning 'three'");
    yield return "three";
}

public bool IsWritable(string path) => false; // testing only 

If I run:

var paths = GetPaths();
Console.WriteLine("Searching for existing file..");
foreach (var path in paths)
{
    if (File.Exists(path))
    {
        Console.WriteLine($"Found existing file '{path}'");
    }
}

Console.WriteLine("Searching for a writable path..");
foreach (var path in paths.Reverse()) // NOTE: paths enumarated twice
{
    if (IsWritable(path))
    {
        Console.WriteLine($"Found writable path '{path}'");
    }
}

Console.WriteLine("No paths found");

If the file "one" exists, we get:

Searching for existing file..
Returning 'one'
Found existing file 'one'

If, however, the files do not exist, we get:

Searching for existing file..
Returning 'one'
Returning 'two'
Returning 'three'
Searching for a writable path..
Returning 'one'
Returning 'two'
Returning 'three'
No paths found

(we wastefully list the results of GetPaths () twice)


One simple fix is ​​to change the first line to:

var paths = GetPaths().ToList();

, one , :

Returning 'one'
Returning 'two'
Returning 'three'
Searching for existing file..
Found existing file 'one'

( , )


() , ?

, , "":

Searching for existing file..
Returning 'one'
Found existing file 'one'

:

Searching for existing file..
Returning 'one'
Returning 'two'
Returning 'three'
Searching for a writable path..
No paths found
+4
2

, . Enumerator, Lazy-, , , , , , Enumerator .

Enumerator ; Enumerator Stream , , .

static System.IO.FileStream fs;
private static void GetFileStream()
{
    if(fs == null) fs = System.IO.File.Open(....);
    return fs;
}

public Enumarable<string> GetLines()
{
    // return an enumerator that uses the result of GetFileStream() and 
    // advances the file pointer. All Enumerables returned by this method
    // will return unique lines from the same file
}
0

, - , System.Linq.Enumerable FirstOrDefault?

    public static bool IsWritable(string path)
    {
        Func<string, bool> canBeWrittenTo = p => true;// (details omitted)
        return System.IO.File.Exists(path) && canBeWrittenTo(path);
    }

:

        var firstWritablePath = GetPaths().FirstOrDefault(path => IsWritable(path));
        if (firstWritablePath != null)
        {
            // Found existing file...
        }
        else
        {
            // No paths found...
        }
0

Source: https://habr.com/ru/post/1655081/


All Articles