So I was learning C# and when I got to the section of Properties, I learned about the one-liner format (ex. public int Property { get; set; }
). After that, I got curious about the String class's Length property and its implementation. When I look at the documentation in https://docs.microsoft.com/en-us/dotnet/api/system.string.length?view=net-6.0, it simply reads public int Length { get; }
even though I would expect a for loop within get
to count the characters.
From what I was able to gather, you don't always need a separate member variable (in this case: private int length
) when defining a property, but I might expect some internal process counting the characters, storing them in length
and then returning that value when get
is called from myString.Length
. Is there some lower level process occurring when the length of the string is counted or am I not seeing something obvious? Just a curious newbie...
CodePudding user response:
Characters are never counted because all constructors of String
class receive the length information one way or another. It's either the length of the literal, or the length of the array passed, or the buffer length explicitly specified.
In fact, it's impossible to count the characters because there's no "null terminator" for .NET strings. Null is another valid character for a string.
CodePudding user response:
The documentation only provides the definition, not the implementation.
Be that as it may, it could have been implemented with a private set;
but it's not. The actual up-to-date source code is currently located here:
// Gets the length of this string
//
// This is an intrinsic function so that the JIT can recognise it specially
// and eliminate checks on character fetches in a loop like:
// for(int i = 0; i < str.Length; i ) str[i]
// The actual code generated for this will be one instruction and will be inlined.
//
public int Length
{
[Intrinsic]
get => _stringLength;
}
So it has a backing field (and the JIT inlines usage of it, but that doesn't matter).
// These fields map directly onto the fields in an EE StringObject. See object.h for the layout.
//
[NonSerialized]
private readonly int _stringLength;
// For empty strings, _firstChar will be '\0', since strings are both null-terminated and length-prefixed.
// The field is also read-only, however String uses .ctors that C# doesn't recognise as .ctors,
// so trying to mark the field as 'readonly' causes the compiler to complain.
[NonSerialized]
private char _firstChar;
These are the only two fields, but the native version of String
is allocated to the full length.
Let's take a look at the StringObject
as defined in the native part of the .NET Runtime.
private:
DWORD m_StringLength;
WCHAR m_FirstChar;
So it's just an int
field that's located before the first character, and it's set on creation of the string, which makes sense: strings are immutable, so it makes little sense to keep recalculating the length.