tags:

views:

131

answers:

4

Possible Duplicate:
Type result with Ternary operator in C#

I ran into this scenario, and there doesn't seem to be a natural way to return a nullable int. The code below gives compilation error because the ternary operator doesn't like null.

public int? userId
{
    get
    {
        int rv;
        return int.TryParse(userIdString, out rv) ? rv : null;
    }
}

So you (or just me) really have to go all the way and spell it all out:

public int? userId
{
    get
    {
        int id;
        if(int.TryParse(userIdString, out id)){
           return id;
        }
        return null;
    }
}

EDIT: Is there a more natural way of instantiating a nullable, to make the ternary operator work?

+9  A: 
public int? userId 
{ 
    get 
    { 
        int rv; 
        return int.TryParse(userIdString, out rv) ? (int?)rv : null; 
    } 
} 
James Curran
+1 for typing faster than I can! :P
md5sum
But apparently, someone didn't like that answer --- I got down-voted (but it seems, he hit you too)
James Curran
Yeah... I've just learned to ignore the down-vote trolls...
md5sum
I downvoted both because I think other answers were better and would like them at the top, and that's what up/down-votes are for. @md5sum, just because you get a downvote it does not mean that the answer is bad. It's just a way to move answers up/down.
Filip Ekberg
@Filip: But Anthony's is just wrong, and Bob's, while correct, merely repeats what the OP already knows, without helping him fix it.
James Curran
@Filip, see it how you wish, but I tend to think downvotes should be reserved for answers that are wrong or while technically correct (meaing, it will work), ill-advised code. Mine *was* wrong, though. At least, in the diagnosis portion!
Anthony Pegram
Just giving code rarely helps the OP, next time he will ask how to do similar things. Some explaining content is always much better than just a code-sample. And also @md5sum's answer is a duplicate and should be deleted therefore also downvoted.
Filip Ekberg
Every time I start to get enthusiastic about SO and try to help people, someone like @Filip comes along and reminds me to not waste my time here, or at least not to believe the SO rep means anything in particular.
gmagana
@Anthony: Actually, I was refering to your "(int?)null" part, which I *thought* was wrong. But after Jon Skeet recommended the same thing, I had to actually try it to prove to myself that it would work.
James Curran
Well, yeah, you can cast either side, but now you've learned casting null to `int?` is valid. You just need to get away from `bool ? int : null`, because the compiler will not automatically say "`int` can be `int?`, `null` can be `int?`, OK, this expression returns `int?`." It will make the leap for one of them when given appropriate info, but not for both.
Anthony Pegram
+1  A: 

You're returning a (non-nullable) int or null in the same expression. You'll need to explicitly return a int? in your ternary expression for that to work.

Bob
+4  A: 
public int? userId
{
    get
    {
        int rv;
        return int.TryParse(userIdString, out rv) ? (int?)rv : null;
    }
}
md5sum
+2  A: 

EDIT: I hadn't read the question carefully enough; the problem isn't that the conditional operator doesn't like nulls - it's that it needs to know what the overall type of the expression should be... and that type has to be the type of either the left-hand side, or the right-hand side. null itself is a type-less expression which can be converted to many types; int is a perfectly valid type, but it's one of the types which null can't be converted to. You can either make the right-hand side explicitly of type int? and get the implicit conversion of int to int? from the left-hand side, or you can perform a cast on the left-hand side, and get the implicit conversion of null to int?.

My answer is like James's, but casting the null instead:

public int? userId 
{ 
    get 
    { 
        int rv; 
        return int.TryParse(userIdString, out rv) ? rv : (int?) null; 
    } 
}

This is to emphasize that it's not a null reference; it's a null value of type int?. At that point, the conversion of the int rv is obvious.

There are two other alternatives along the same lines to consider though:

return int.TryParse(userIdString, out rv) ? rv : new int?(); 

return int.TryParse(userIdString, out rv) ? rv : default(int?); 

Personally I think the "casted null" is the nicest form, but you can make up your own mind.

Another alternative would be to have a generic static method:

public static class Null
{
    public static T? For<T>() where T : struct
    {
        return default(T?);
    }
}

and write:

return int.TryParse(userIdString, out rv) ? rv : Null.For<int>(); 

I don't think I really like that, but I offer it for your inspection :)

Jon Skeet
I like the in-depth approach here... question though: Is the casting of the null to `int?` for the compiler or for the developers?
md5sum
@md5sum: Both... without it, the compiler won't know which type to use for the overall conditional expression.
Jon Skeet
@md5sum, when given `bool ? int : null`, the compiler will not leap to say *both* are convertible to `int?`. It will make the leap for one of them and say `int` can be `int?` or `null` can be `int?`, but you need to plant the `int?` suggestion in the compiler's brain, so to speak.
Anthony Pegram