Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to differ between empty Platform.String and null Platform.String^

We're verifying that method arguments aren't null upon function entry, but this doesn't work for Platform::String (or Platform.String, no difference between C# or C++), since they overload the semantics of an empty string with a null instance.

Consider this, where the exception will always be thrown:

auto emptyString = ref new Platform::String();

// Now, emptyString.IsEmpty() will be true

if (emptyString == nullptr)
{
    throw ref new Platform::InvalidArgumentException();
}

The variable has a non-null value, but the == comparison operator is overloaded so comparing it to nullptr returns true since the String instance is empty.

As far as I can see this makes it impossible for us to make proper null checks at function entry for Strings. Is that really so?

like image 424
Johann Gerell Avatar asked Aug 31 '12 11:08

Johann Gerell


2 Answers

There are no "null strings" in Windows Runtime. "Null" and "empty" mean the same thing with respect to strings.

Despite the fact that Platform::String uses the ^ syntax and looks like a reference type, it's not: it's a projection of a Windows Runtime fundamental type, HSTRING. A "null" HSTRING is indistinguishable from an empty HSTRING.

Even if a Platform::String^ appears to be "null" (e.g. in the debugger), it is safe to treat it as if it were an empty string. You can use it for concatenation, call s->Length(), etc.


In C#, a string can be null (and you can thus test it for null), but you will never get a null string from a Windows Runtime call and you cannot pass a null string as an argument to a Windows Runtime function (doing so will yield an exception at the ABI boundary).

like image 139
James McNellis Avatar answered Nov 15 '22 10:11

James McNellis


Seems that you are right. Any string which is set to nullptr is treated as an empty string. And if you even pass nullptr to the function you will never get the NullReferenceException.

bool NullPtrTest(Platform::String^ value)
{
  return value == nullptr;
}

bool EmptyTest(Platform::String^ value)
{
  return value->IsEmpty();
}

bool ReferenceEqualsWithNullPtrTest(Platform::String^ value)
{
  return Platform::String::ReferenceEquals(nullptr, value);
}

bool EqualsWithValueTest(Platform::String^ value)
{
  return value->Equals("test");
}

//...

NullPtrTest(nullptr); // true
NullPtrTest(ref new Platform::String()); // true
NullPtrTest("test"); // false


EmptyTest(nullptr); // true - no exception
EmptyTest(ref new Platform::String()); // true
EmptyTest("test"); // false


ReferenceEqualsWithNullPtrTest(nullptr); // true
ReferenceEqualsWithNullPtrTest(ref new Platform::String()); // true
ReferenceEqualsWithNullPtrTest("test"); // false


EqualsWithValueTest(nullptr); // false - no exception
EqualsWithValueTest(ref new Platform::String()); // false
EqualsWithValueTest("test"); // true

So, I see no way to find out whether the string was ever nullptr.

like image 29
ie. Avatar answered Nov 15 '22 11:11

ie.