33
\$\begingroup\$

This is an extension method to get a string that is truncated to a maximum length.

Any comments?

public static class StringExtensions
{
    public static string WithMaxLength(this string value, int maxLength)
    {
        if (value == null)
        {
            return null;
        }

        return value.Substring(0, Math.Min(value.Length, maxLength));
    }
}
\$\endgroup\$
14
  • 1
    \$\begingroup\$ No, that's pretty much as good as it gets. There isn't much to say about this few code. \$\endgroup\$ Aug 15, 2015 at 12:16
  • \$\begingroup\$ Isn't it a bit inconsistent that WithMaxLength(null, 1) doesn't throw an exeption whereas WithMaxLength("", 1) would? \$\endgroup\$ Aug 15, 2015 at 19:16
  • 1
    \$\begingroup\$ @KonradMorawski neither would throw an exception. WithMaxLength(null, 1) would return null and WithMaxLength("", 1) would return ""... \$\endgroup\$
    – Jakob
    Aug 15, 2015 at 19:30
  • 1
    \$\begingroup\$ For what purpose do you truncate? How do you define length? Which kind of sequences do you want to keep intact (e.g. code-points or even text-elements)? \$\endgroup\$ Aug 16, 2015 at 9:11
  • 1
    \$\begingroup\$ @CodesInChaos I have a legacy system where settings for actions are stored in a table with a long description. Then when a action is performed the description is saved in several places with different maximum lengths in the database and I just want to save what is room for and discard the rest. \$\endgroup\$
    – Jakob
    Aug 17, 2015 at 16:13

4 Answers 4

45
\$\begingroup\$

If you're using C# 6.0, I believe you can drop the null-check:

public static string WithMaxLength(this string value, int maxLength)
{
    return value?.Substring(0, Math.Min(value.Length, maxLength));
}

Other than that, it's like Jeroen said: that's pretty much as good as it gets.

The class and parameter naming is exactly as I'd have it, and the name of the extension method is decent, although I'd try to find a name that better indicates that truncation will occur when value is longer than maxLength... but WithMaxLength isn't a bad name.

\$\endgroup\$
4
  • 4
    \$\begingroup\$ I agree with you regarding naming. The method truncates a string, if needed, and the naming should reflect that. If I were to use something named WithMaxLength, I might expect the returned to string to actually have maxLength even if I pass string.Empty as the input value. \$\endgroup\$
    – Rick Davin
    Aug 15, 2015 at 15:07
  • 1
    \$\begingroup\$ "Keep" or "Left" are common names for such a method. \$\endgroup\$ Mar 7, 2019 at 9:48
  • 1
    \$\begingroup\$ The function allows negative values for maxLength, which is unhandled and produces unexpected results (same issue as for the code provided by the question). \$\endgroup\$
    – Matt
    May 15, 2020 at 12:44
  • \$\begingroup\$ Using the C# 8 range .. operator: => value?[..Math.Min(value.Length, maxLength)]; \$\endgroup\$ Jan 7, 2023 at 21:47
12
\$\begingroup\$

There is an inconsistency - negative values of maxLength would be forgiven for value being null, but cause an exception for every other input (since Substring would throw an ArgumentOutOfRangeException).

There's two possible approaches that remove this inconsistency - fail fast

public static string WithMaxLength(this string value, int maxLength)
{
    if (maxLength < 0)
    {
       throw new ArgumentOutOfRangeException("maxLength must be equal to or greater than 0");
    }
    // ...

Or ignore negative values for both cases:

public static string WithMaxLength(this string value, int maxLength)
{
    if (value == null)
    {
        return null;
    }
    if (maxLength < 0)
    {
        return "";
    }
    return value.Substring(0, Math.Min(value.Length, maxLength));
}

Personally I'd be inclined to choose the former - maxLength being smaller than 0 could be a symptom of a problem (implementation error) that we wouldn't want to sweep under the carpet. It's also consistent with the way Substring itself behaves.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Correct! Good catch. One small improvement: Remove the null-checking if statement, then modify the return statement as follows: return value?.Substring(0, Math.Min(value.Length, maxLength));; will do the same, but much shorter. :-) \$\endgroup\$
    – Matt
    May 15, 2020 at 12:47
  • 1
    \$\begingroup\$ My answer was posted 5 years ago, I'm not sure if C# 6.0 (which introduced the null-safety operator) had been released back then yet ;) Obviously I agree that's the way to go now - as in the accepted answer \$\endgroup\$ May 16, 2020 at 13:55
  • \$\begingroup\$ Your answer is still valid, and I agree, null-checking operators where introduced late in C#. The accepted answer does not check for maxLength < 0, and I like the fail fast approach you mentioned. So my hint was only for the null-checking. By the way, I am looking for a truncate parameter for the .ToString() method, because I think truncating after .ToString() is inefficient. Do you have an idea how that can be achieved? Recall that .ToString() can be invoked on every object or primitive type. \$\endgroup\$
    – Matt
    May 18, 2020 at 7:05
8
\$\begingroup\$

Well, Mat's Mug already gave the only improvement for the code in the extension-method I could find, using the conditional-member-access operator.

Aside from that, there's only the methods name. Which is far too long and awkward.
Truncate has a nice ring to it, and everybody understands it.

public static class StringExtensions
{
    public static string Truncate(this string value, int maxLength)
    {
        return value?.Substring(0, Math.Min(value.Length, maxLength));
    }
}
\$\endgroup\$
5
\$\begingroup\$

Per Mat's Mug's answer:

I'd try to find a name that better indicates that truncation will occur when value is longer than maxLength... but WithMaxLength isn't a bad name.

I disagree that the method's name is the place to do this. It's not. And WithMaxLength is a perfectly fine name.

But... that truncation occurs should be documented. I'm not sure what's available exactly for C#, but most all languages have a format for showing in-IDE documentation.

I've been told the C# version of this looks something like this:

<summary>
This function does something.
<param name="string">The string to do things with</param>
</summary>

We should certainly add this sort of documentation to our method to be clear on exactly what happens with the method. I think any other sort of name for the method itself goes beyond to descriptive and ventures into the realm of too verbose (and this is coming from someone who writes Objective-C...).

\$\endgroup\$
1
  • \$\begingroup\$ I think you're looking for the <Remarks> tag. \$\endgroup\$
    – RubberDuck
    Aug 15, 2015 at 17:33

Not the answer you're looking for? Browse other questions tagged or ask your own question.