Search code examples
c#stringrangesubstringindices

C# 8 way to get last n characters from a string


Recently VS hinted me to use the:

var str = "foo";
var str2 = str[^2..];

Instead of the:

var str = "foo";
var str2 = str.Substring(str.Length - 2);

So, my question is are there any differences between the str[^2..] and the str.Substring(str.Length - 2)? I think it is a new C# feature, but I was not able to find any documentation about it. So, I do not know how it is called and what version of C# does it come with.

Here is what I was trying to google:

^ in string access c#

I did not get any related results. Should I google something else?


Solution

  • Others are correct in that it is just syntax sugar but there is some slight differences. They both call "Substring" however the hat version calls the String.Substring(Int32, Int32) signature and the later conventional version calls String.Substring(Int32) signature.

    SharpLab example.

    It's interesting that even though str[^2..] produces more code it seems to have slightly better performance in my quick benchmark.

    var str = "foo";
    var str2 = str[^2..];
    ========generates the following IL=============
       nop  
       ldstr    "foo"
       stloc.0     // str
       ldloc.0     // str
       dup  
       callvirt String.get_Length ()
       dup  
       ldc.i4.2 
       sub  
       stloc.2  
       ldloc.2  
       sub  
       stloc.3  
       ldloc.2  
       ldloc.3  
       callvirt String.Substring (Int32, Int32)
       stloc.1     // str2
       ldloc.1     // str2
       call Console.WriteLine (String)
       nop  
       ret
    

    And the following conventional version.

    var str = "foo";
    var str2 = str.Substring(str.Length - 2);
    ========generates the following IL=============
       nop  
       ldstr    "foo"
       stloc.0     // str
       ldloc.0     // str
       ldloc.0     // str
       callvirt String.get_Length ()
       ldc.i4.2 
       sub  
       callvirt String.Substring (Int32)
       stloc.1     // str2
       ldloc.1     // str2
       call Console.WriteLine (String)
       nop  
       ret