DEV Community

Tim Abell
Tim Abell

Posted on • Originally published at timwise.co.uk on

Always Add Argument Names - C#

An argument (lol) for the use of explicit argument names in C# function calls even when they seem redundant.

  1. You can assert correctness when reviewing the call site in a dumb text display (e.g. a patch in a github pull request)
  2. Parameter-order refactoring won’t introduce subtle bugs and breaking changes.

This is particularly important when you have multiple arguments of the same type.

It’s also a good idea when the call doesn’t immediately make it obvious what the meaning of the parameter is. E.g. Foo(3) vs Foo(sizeInMeters: 3).

No argument names (bad)

Starting point:

void Main()
{
    Foo("Home", "Blah"); // don't do this
}

void Foo(string importantThing, string otherThing)
{
    switch (importantThing)
    {
        case "Home":
            DoSomething();
            break;
        default:
            DoSomethingElse();
            break;
    }
    Log(otherThing);
}

Enter fullscreen mode Exit fullscreen mode

If Foo() is defined in a different file it’s hard to eyeball Main() and tell if the arguments line up properly.

If I now re-order the arguments of Foo() can you easily spot that the call site in Main() is now incorrect?

void Main()
{
    Foo("Home", "Blah"); // Now broken!! But can you tell?
}

void Foo(string otherThing, string importantThing) // <-- parameters flipped
{
    switch (importantThing)
    {
        case "Home":
            DoSomething();
            break;
        default:
            DoSomethingElse();
            break;
    }
    Log(otherThing);
}

Enter fullscreen mode Exit fullscreen mode

With argument names (good)

Starting point:

void Main()
{
    Foo(importantThing: "Home", otherThing: "Blah");
}

void Foo(string importantThing, string otherThing)
{
    switch (importantThing)
    {
        case "Home":
            DoSomething();
            break;
        default:
            DoSomethingElse();
            break;
    }
    Log(otherThing);
}

Enter fullscreen mode Exit fullscreen mode

You can now easily see that "Home" is going to "importantThing", even in a plain-text view of the file.

If I now re-order the arguments of Foo() again, it doesn’t break because the compiler knows which string to connect to which parameter. Win.

void Main()
{
    Foo(importantThing: "Home", otherThing: "Blah"); // still valid!

}

void Foo(string otherThing, string importantThing) // <-- refactored
{
    switch (importantThing)
    {
        case "Home":
            DoSomething();
            break;
        default:
            DoSomethingElse();
            break;
    }
    Log(otherThing);
}

Enter fullscreen mode Exit fullscreen mode

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay