Why can't we define a variable inside an if statement?

Viewed 71688

Maybe this question has been answered before, but the word if occurs so often it's hard to find it.

The example doesn't make sense (the expression is always true), but it illustrates my question.

Why is this code valid:

StringBuilder sb;
if ((sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

But this code isn't:

if ((StringBuilder sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

I found a similar question regarding a while statement. The accepted answer there says that in a while statement, it would mean the variable would be defined in each loop. But for my if statement example, that isn't the case.

So what's the reason we are not allowed to do this?

6 Answers

Try C#7's Pattern Matching.

Using your example:

if (new StringBuilder("test") is var sb && sb != null) {
    Console.WriteLine(sb);
}

C# 7.0 introduced ability to declare out variables right inside conditions. In combination with generics, this can be leveraged for the requested result:

public static bool make<T> (out T result) where T : new() {
    result = new T();
    return true;
}
// ... and later:
if (otherCondition && make<StringBuilder>(out var sb)) {
    sb.Append("hello!");
    // ...
}

You can also avoid generics and opt for a helper method instead:

public static bool makeStringBuilder(out StringBuilder result, string init) {
    result = new StringBuilder(init);
    return true;
}
// ... and later:
if (otherCondition && makeStringBuilder(out var sb, "hi!")) {
    sb.Append("hello!");
    // ...
}

I was redirected from another "duplicated" question: Declare variable in one line if statement . I do not think answers of this question can properly cover it.

If you are looking for a way to avoid repeating very long path and find it's impossible to define a variable inside if(), try also :

    var email = User.Current.Very.Complex.Path?.Email??"default@mail.com";

it equals to:

    string email = null;
    if (User.Current.Very.Complex.Path != null)
         email = User.Current.Very.Complex.Path.Email
    if (email == null)
         email = "default@mail.com";
Related