Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Multi-Parsing of same file with different defines. #75537

Open
JackTheSpades opened this issue Oct 16, 2024 · 1 comment
Open

Allow Multi-Parsing of same file with different defines. #75537

JackTheSpades opened this issue Oct 16, 2024 · 1 comment
Labels
Area-Language Design untriaged Issues and PRs which have not yet been triaged by a lead

Comments

@JackTheSpades
Copy link

Defines can be added for projects or individual files. I propose the ability to have the same source file included multiple times with different defines being present/absent for each parsing.

The main reason why this would be desirable is to have the ability to provide async support without having to write the common parts of the method/class twice. Using partial classes one could simple use the preprocessor directives to provide a different method signature/head and call the corresponding await/async methods when necessary.

Here a quick example of what this would look like.

// class needs to be partial
partial class StreamHelper
{
#if Async
    public static async IAsyncEnumerable<T> ParseLinesAsync<T>(Stream stream, IStringParser<T> parser, [EnumeratorCancellation] CancellationToken cancellationToken)
#else
    public static IEnumerable<T> ParseLines<T>(Stream stream, IStringParser<T> parser)
#endif
    {
        using StreamReader sr = new StreamReader(stream, leaveOpen: true);
        string? line;

        while (true)
        {
#if Async
            line = await sr.ReadLineAsync(cancellationToken).ConfigureAwait(false);
#else
            line = sr.ReadLine();
#endif

            // break at end-of-stream
            if (line is null)
                break;
            // line comment starts with #
            if (line.SkipWhile(c => char.IsWhiteSpace(c)).FirstOrDefault() is '#')
                continue;

            yield return parser.Parse(line);
        }
    }
}

While async is the most common example one would think of, it could also be used in methods that require 99% the same code but only differ somewhere in the middle, with no convenient way to just repurpose the code. I believe, at the moment, this is usually done by adding a private _Internal method with a delegate to handle the task specific situations.

public void DoThingA(object param1, object param2) => DoThingCommonInternal(param1, param2, DoThingAInternal);
public void DoThingB(object param1, object param2) => DoThingCommonInternal(param1, param2, DoThingBInternal);

private void DoThingCommonInternal(object param1, object param2, Action handler)
{
    // common part for A and B

    handler();

    // common part for A and B
}
private void DoThingAInternal() { /* Handler for A specific things */ }
private void DoThingBInternal() { /* Handler for B specific things */ }

When it could be shrunken down to this:

#if THING_A
public void DoThingA(object param1, object param2)
#else
public void DoThingB(object param1, object param2)
#endif
{
    // common part for A and B

#if THING_A
    { /* Handler for A specific things */ }
#else
    { /* Handler for B specific things */ }
#endif

    // common part for A and B
}

Admittedly, whether this is better or worse depends a lot on how different ThingA and ThingB here really are.

A feature like this could be provided either on the necessary file itself, similar to how defines are provided now. Like #multipass Async. Or through the csproj file. Ideally though, the IDE would have to show all different renditions of the file with the different defines being active:

For example: Having #multipass Async;Custom on the file StreamHelper.cs could show up as:

Image

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Language Design untriaged Issues and PRs which have not yet been triaged by a lead labels Oct 16, 2024
@lsoft
Copy link

lsoft commented Oct 17, 2024

@JackTheSpades side note: fyi if you need to have async and sync versions of the same method, this can be easily achieved with this source generator. No need to wait new Roslyn stuff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Language Design untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

No branches or pull requests

2 participants