Skip to content

Inconsistencies with null-coalescing wrapping on method chains #1573

@SigtryggurO

Description

@SigtryggurO

csharpier 0.30.6

Input:

var test4 =
    await context
        .Images.Where(x => x.Id == ImageId.CreateUnique() && x.Created == DateTime.MaxValue)
        .FirstOrDefaultAsync(cancellationToken) ?? throw new Exception("This is an exception message");

Output:

var test4 =
    await context
        .Images.Where(x => x.Id == ImageId.CreateUnique() && x.Created == DateTime.MaxValue)
        .FirstOrDefaultAsync(cancellationToken) ?? throw new Exception("This is an exception message");

Expected behavior:

var test4 =
    await context
        .Images.Where(x => x.Id == ImageId.CreateUnique() && x.Created == DateTime.MaxValue)
        .FirstOrDefaultAsync(cancellationToken)
    ?? throw new Exception("This is an exception message");

On its own, this might seem fine, but when compared to a similar method where we modify different parts of the assignment, the inconsistency becomes apparent:

// Fully inline: short method chain and short exception message.
var test1 = await context.Images.FirstAsync(cancellationToken) ?? throw new Exception("This is an exception message");

// Break after '=', everything else fits on one line.
var test2_1 =
    await context.Images.FirstOrDefaultAsync(cancellationToken) ?? throw new Exception("This is an exception message");

// Similar to test2_1, slightly longer exception message but still contained in a single line.
var test2_2 =
    await context.Images.FirstAsync(cancellationToken) ?? throw new Exception("This is a longer exception message");

// Breaks after '=', and '??' is on a new line due to method length.
var test3_1 =
    await context.Images.FirstOrDefaultAsync(x => x.Id == ImageId.CreateUnique(), cancellationToken)
    ?? throw new Exception("This is an exception message");

// Similar to test3_1, but it wraps due to message length.
var test3_2 =
    await context.Images.FirstAsync(cancellationToken)
    ?? throw new Exception("This is a much longer exception message which should be long enough to wrap on its own");

// Multiline formatting: Last part of method chain is short and the exception message is short, so '??' is not wrapped, inconsistent with others.
var test4 =
    await context
        .Images.Where(x => x.Id == ImageId.CreateUnique() && x.Created == DateTime.MaxValue)
        .FirstOrDefaultAsync(cancellationToken) ?? throw new Exception("This is an exception message");

// Multiline formatting: Last part of method chain is long, so '??' is wrapped.
var test5_1 =
    await context
        .Images.Where(x => x.Id == ImageId.CreateUnique() && x.Created == DateTime.MaxValue)
        .FirstOrDefaultAsync(x => x.Id == ImageId.CreateUnique(), cancellationToken)
    ?? throw new Exception("This is an exception message");

// Multiline formatting: Exception message is long, so '??' is wrapped.
var test5_2 =
    await context
        .Images.Where(x => x.Id == ImageId.CreateUnique() && x.Created == DateTime.MaxValue)
        .FirstOrDefaultAsync(cancellationToken)
    ?? throw new Exception("This is a much longer exception message which should be long enough to wrap on its own");

I also tried without assignment and swapped out throw for a static function with same results.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions