Generally the purpose behind throwing the exception yourself is to provide your own personal exception. For example, if
Truncate were a method available to use in a library, lets call it ABC, it might be nice to have all your exceptions fall under a base exception called
ABCException which also comes from the library. In other words, for any problems caused by library ABC, you can optionally catch it using the base exception
ABCException. This is extremely useful to identify problems coming from a specific library.
Another reason to perform your own check is for a "sanity check". In other words, yes, perhaps
Substring throws this exception, but should you decide tomorrow that something should be done prior to performing the actual
Substring call, your code may throw a different and uncaught exception instead. This may make debugging the problem that much more difficult since you may discard the possibility of the problem being in
Truncate because of the fact that
Truncate is supposed to throw another exception in such circumstances. Call it what you will, but I like to call it defensive programming. Is this likely? No, but if it is only going to cost you 10 seconds to add, I'd say to go ahead and add it.
Note that I wouldn't add checks like these unless they were public methods and therefore available to be called by anyone. Also, in circumstances in which the method is specifically documented as such, I wouldn't even perform checks. If the caller fails to respect the documentation for said method, it is the caller's responsibility, not yours.
Also, if I may make a minor optimization, the contents of the if statement should be the most likely scenario rather than the least likely. That said, I would rewrite it:
public static string Truncate(string value, int maxLength)
if(maxLength > 0 && !string.IsNullOrEmpty(value))
return value.Length <= maxLength ? value : value.Substring(0, maxLength);
throw new ArgumentOutOfRangeException("maxLength");
Hope that helps!