// Determines whether two Strings match. public static bool Equals(string?a, string?b) { // Transform 'str == ""' to 'str != null && str.Length == 0' if either a or b are jit-time // constants. Otherwise, these two blocks are eliminated if (RuntimeHelpers.IsKnownConstant(a) && a != null && a.Length == 0) { return(b != null && b.Length == 0); } if (RuntimeHelpers.IsKnownConstant(b) && b != null && b.Length == 0) { return(a != null && a.Length == 0); } if (object.ReferenceEquals(a, b)) { return(true); } if (a is null || b is null || a.Length != b.Length) { return(false); } return(EqualsHelper(a, b)); }
public bool EndsWith(char value) { // If the string is empty, *(&_firstChar + length - 1) will deref within // the _stringLength field, which will be all-zero. We must forbid '\0' // from going down the optimized code path because otherwise empty strings // would appear to end with '\0', which is incorrect. // n.b. This optimization relies on the layout of string and is not valid // for other data types like char[] or Span<char>. if (RuntimeHelpers.IsKnownConstant(value) && value != '\0') { // deref Length now to front-load the null check; also take this time to zero-extend // n.b. (localLength - 1) could be negative! nuint localLength = (uint)Length; return(Unsafe.Add(ref _firstChar, (nint)localLength - 1) == value); } int lastPos = Length - 1; return(((uint)lastPos < (uint)Length) && this[lastPos] == value); }