I'm not sure there would be a definitive answer to this unless someone from the BCL team has a story to tell.
Some considerations might be:
- Changing the methods would constitute a large breaking change to existing code bases with very little (debatable if any) gain. Some might argue that it would be a detriment for the reasons below.
- Nullable types
box the wrappedwrap the underlying value causing a (minor) performance hit always even when you expect your parse to succeed and don't want a nullable type anyway. - If you know your input is supposed to be valid, then the
Parse
method throws exceptions for the exceptional case that the input is invalid. This is generally more performant as we don't have extra error handling code for when we don't need it, and expected from a design point of view. If you plan on handling the invalid case, that's whatTryParse
is for. - Confusion between
int Parse(string, int? defaultValue)
andint Parse(string)
, mostly with regards to their error handling. Notice I've remove the optional part of the first method otherwise it would make no sense to have both methods (you would never be able to call your method without explicitly passing innull
). At this point, it would be a bit confusing as one overload throws an exception on failure whereas the other one does not. There are a few exceptions to this, such as Type.GetType but they're generally rare and in such cases they make use of an explicitly named parameter indicating that it will or will not throw an exception. - Another benefit of
TryParse
as designed is that it is pretty explicit by way of its API for handling the pass/fail result. Rather than a magic number/result (null
) indicating a failure, it returns a separate true/false value. Now, some mechanisms do this (String.IndexOf
for example returning -1) so it's debatable if this is a good thing or a bad thing. Depending on your practice, using the returntrue/false
value might be easier, or using the magicnull
result might be. But they decided I guess to not muddy the waters with two methods doing the exact same thing but with slightly different signatures/return values. Another consideration is how common nullable value types are. Are you really using
Int32?
in many places? Or is it just for error/input handling? In my experience, nullable values are mostly used for database I/O (and even then, not that often). The only other times could be for input from non-trusted sources which would only be for the initial interfacing; all underlying code would still be typed against the non-nullableInt32
. In such case you have two methods, the original:int input; if (TryParse(someString, out input)) DoSomethingValid(input); //valid! Do something else ErrorMessage()//not valid, error!
Or your suggestion:
int? input = Parse(someString) if (input != null) DoSomethingValid(input.GetValueOrDefault())//valid! Do something else ErrorMessage()//not valid, error!
Note how similar both are. Your suggestion really provides very little, if anything to this case. Also note the usage of
GetValueOrDefault()
, this is actually the faster/better way to access the wrapped value if you know it's non-null, but rarely (at least from what I see on the internet) is it used over theValue
accessor. If the BCL added/changed theParse
method as you suggest, I think a lot of people would be unnecessarily hitting theValue
accessor.I can't comment specifically on cases using nullable values significantly throughout an application design and/or its layers, but in my experience they are rarely used or should be rarely used (to me, it's a code smell almost on the level of "stringly-typed" data)
Ultimately, I believe part of the reason why extension methods were added (aside from Linq) was to allow users to roll their own API as needed. In your case, you can easily add an extension method to obtain the syntax you want:
public static Int32? Parse(this String s, Int32? defaultValue = null)
{
Int32 temp;
return !Int32.TryParse(s, out temp)
? defaultValue
: temp;
}
string validString = "1";
int? parsed = validString.Parse(); //1
int? failParsed = "asdf".Parse(9); //9
The teams generally favour maintaining the status quo and additions have to provide a significant enough benefit to be added to the system, and the team also considers what workarounds already exist in the API as-is. I'd suggest that given the extension method option, it's not that big of a concern to change the API considering the signficant breaking nature of it.