简体   繁体   中英

Are the results of `IncrementalValueProvider` extensions cached and compared?

SyntaxValueProvider.CreateSyntaxProvider takes two Func arguments: a predicate that filters the syntax elements, and a transform that returns the interesting details from the syntax context. The result sets from each Func are cached and compared with previous invocations to avoid unnecessary regeneration.

CreateSyntaxProvider returns an IncrementalValuesProvider , which has several extension methods that look like LINQ but aren't. Are the result sets from these extensions also cached and compared, potentially preventing regeneration if their output is unchanged?

In many tutorials, the transform returns either the interesting details from the syntax context, or null. The nulls are then removed with a pseudo-LINQ Where :

var provider = context.SyntaxProvider.CreateSyntaxProvider(
        (syntax, _) => Predicate(syntax), 
        (syntaxContext, _) => DetailsOrNull(syntaxContext))
    .Where(details => details != null);
initContext.RegisterSourceOutput(provider, (spc, details) => Generate(spc, details));

What I'm getting at with this question is whether the following would be equivalent in terms of preventing Generate from being called:

var provider = context.SyntaxProvider.CreateSyntaxProvider(
        (syntax, _) => Predicate(syntax), 
        (syntaxContext, _) => syntaxContext
    .Where(syntaxContext => IsInteresting(syntaxContext))
    .Select((syntaxContext, _) => Details(syntaxContext));
initContext.RegisterSourceOutput(provider, (spc, details) => Generate(spc, details));

This would be less efficient if IsInteresting and Details extract the same information from syntaxContext . But if they don't duplicate work, is there any reason to do it the first way?

As far as I understand the whole thing is a pipeline with several steps. Each step of the pipeline represents a stage which has input/output cached. I don't think that the clarify that, however Andrew Lock's blog post describes that well. The LINQ-like extension method .Where is step 4.

It's important to understand the pipeline we've defined so far:

  1. Start with all the syntax in the program
  2. Quickly restrict to only methods that have an attribute
  3. Transform each syntax to either the parent class, if the method has the [LoggerMessage] attribute, or return null.
  4. Filter out null values.

Stages 2-4 will run a lot, basically for every edit you make in your IDE. But unless you're actually adding something that will change generation, ie a method with the [LoggerMessage] attribute, the output of step 4 will remain constant. That means nothing else in your generator needs to execute. This is a really powerful point, as it can massively reduce the amount of work that needs to happen.

Also image from the blog post:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM