Reputation: 1276
As far as I know, int.TryParse(string, out int)
exists since Framework 2.0. So does int?
.
Is there a reason to use an out
parameter instead of returning an int?
with HasValue
set to true
of false
depending on the ability to convert ?
Upvotes: 19
Views: 1438
Reputation: 149538
Here's a quote from Julie Lerman's blog (Back from 2004):
I have played with
nullable
in the March preview bits, but not yet in the May and disappointed with the current (but slated for serious improvement by the bcl team!!!) performance when I compared the usingnullable<t>
over current options. So for example with value types:comparing
myNullableInt.HasValue
to (in VB) ismyInt < 0
or with reference types
comparing
myNullableThing.HasValue
to “if not myThing=null
”the nullable type is currently much much slower. I have been promised by a few on the BCL team that the plan is to make the nullable MUCH more performant.
I have also been given the hint that in the future, the following will be possible:
Nullable<T> Parse(string value); Nullable<Int32> i = Int32.Parse( some String );
And will be more performant than
TryParse
. So that, too will be interesting.
I assume that as always, the benefit outweighs the cost.
Anyway, in the upcoming C# vNext, you can do:
DateTime.TryParse(s, out var parsedDateTime);
Turning TryParse into a one liner.
Upvotes: 5
Reputation: 20722
I cannot tell about the actual reasons, but I see three possible reasons:
1) Nullable types were introduced in .NET 2.0, while the first TryParse
methods were already around since .NET 1.1. Thus, when nullable types were introduced, it was too late for such an API change; and new classes wouldn't implement TryParse
differently because the pattern had already been set.
2) Not all types can be used with the Nullable
structure, only value types can. However, there are methods following the Try*
pattern that have to return reference types. For example, a dictionary may totally legitimately contain null
as an item, hence its TryGetValue
method needs an additional way to express that a key was not found.
3) The way the Try*
-methods are written, it is possible to write code like this:
int myValue;
if (int.TryParse("42", out myValue)) {
// do something with myValue
}
// do something else
}
Now, imagine if TryParse
only returned an int?
. You can either dispose of the myValue
variable and lose the result:
if (int.TryParse("42").HasValue) {
// do something with ... what? You didn't store the conversion result!
}
// do something else
}
Or you can add a nullable variable:
int? myValue = int.TryParse("42");
if (myValue.HasValue) {
// do something with myValue.Value
}
// do something else
}
This isn't an advantage over the current version any more, and instead it requires writing myValue.Value
at some later instances, where otherwise a simple value
would have sufficed. Note that in many cases, you only need the information about whether the operation was successful for the if
statement.
Upvotes: 21
Reputation: 1062560
One other possible reason:
Generics for .NET and C# in their current form almost didn't happen: it was a very close call, and the feature almost didn't make the cut for Whidbey (Visual Studio 2005). Features such as running CLR code on the database were given higher priority.
...
Ultimately, an erasure model of generics would have been adopted, as for Java, since the CLR team would never have pursued a in-the-VM generics design without external help.
My point being: the majority of changes in the BCL (or at least those not directly related to generics) probably needed to work both with and without generics, in case that feature was cut in the final RTM.
Of course, this also makes sense from a calling client perspective: all the consuming languages (ok, there weren't as many back then) would ideally have been able to use them - and out
parameters weren't as cutting-edge as generics.
Upvotes: 4
Reputation: 7140
The simple reason is because when int.TryParse
was added to the language, Nullable<T>
didn't exist.
In this blog post by Eric Lippert, there's a line towards the bottom that reads:
The solution is to write your own extension method version of TryParse the way it would have been written had there been nullable value types available in the first place
which makes it clear that nullable types were not available to be used in the original implementation of TryParse
. Eric Lippert was on the team that wrote the C# compiler, so I'd say that's a pretty authoritative source.
Upvotes: 24
Reputation: 12092
As to reasons we can only guess, but some possible reasons are:
Assignment overhead: a boxed value incurs some (small) performance overhead over a built in type.
No real gains:
int res;
if int.TryParse("one", out res) {
//something
}
isn't much worse than
int? res = int.TryParse("one");
if (res.HasValue){
int realres = res.Value
//something
}
Upvotes: 3