I would guess that this is a historical artifact.
In the 3.5 version, the GUID is constructed in-place, with all of the text parsing all included within the constructor method itself.
I would guess that at one point the developers decided to refactor all of the parsing code out into helper methods1, at which point they'd have hit a compiler error because you have to definitely assign this
before calling instance methods.
The GuidResult
helper structure seems to have been introduced at some other point in time, at which point these parsing methods could then become static
and work against the GuidResult
rather than the actual Guid
currently being constructed - at which point everything becomes simplified again and that definite assignment isn't required.
This is what reflector decompiles the 3.5 version to:
public Guid(string g)
{
if (g == null)
{
throw new ArgumentNullException("g");
}
int startIndex = 0;
int parsePos = 0;
try
{
int num2;
long num3;
if (g.IndexOf('-', 0) >= 0)
{
string str = g.Trim();
if (str[0] == '{')
{
if ((str.Length != 0x26) || (str[0x25] != '}'))
{
throw new FormatException(Environment.GetResourceString("Format_GuidInvLen"));
}
startIndex = 1;
}
else if (str[0] == '(')
{
if ((str.Length != 0x26) || (str[0x25] != ')'))
{
throw new FormatException(Environment.GetResourceString("Format_GuidInvLen"));
}
startIndex = 1;
}
else if (str.Length != 0x24)
{
throw new FormatException(Environment.GetResourceString("Format_GuidInvLen"));
}
if (((str[8 + startIndex] != '-') || (str[13 + startIndex] != '-')) || ((str[0x12 + startIndex] != '-') || (str[0x17 + startIndex] != '-')))
{
throw new FormatException(Environment.GetResourceString("Format_GuidDashes"));
}
parsePos = startIndex;
this._a = TryParse(str, ref parsePos, 8);
parsePos++;
this._b = (short) TryParse(str, ref parsePos, 4);
parsePos++;
this._c = (short) TryParse(str, ref parsePos, 4);
parsePos++;
num2 = TryParse(str, ref parsePos, 4);
parsePos++;
startIndex = parsePos;
num3 = ParseNumbers.StringToLong(str, 0x10, 0x2000, ref parsePos);
if ((parsePos - startIndex) != 12)
{
throw new FormatException(string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Format_GuidInvLen"), new object[0]));
}
this._d = (byte) (num2 >> 8);
this._e = (byte) num2;
num2 = (int) (num3 >> 0x20);
this._f = (byte) (num2 >> 8);
this._g = (byte) num2;
num2 = (int) num3;
this._h = (byte) (num2 >> 0x18);
this._i = (byte) (num2 >> 0x10);
this._j = (byte) (num2 >> 8);
this._k = (byte) num2;
}
else if (g.IndexOf('{', 0) >= 0)
{
int num5 = 0;
int length = 0;
g = EatAllWhitespace(g);
if (g[0] != '{')
{
throw new FormatException(Environment.GetResourceString("Format_GuidBrace"));
}
if (!IsHexPrefix(g, 1))
{
throw new FormatException(string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Format_GuidHexPrefix"), new object[] { "{0xdddddddd, etc}" }));
}
num5 = 3;
length = g.IndexOf(',', num5) - num5;
if (length <= 0)
{
throw new FormatException(Environment.GetResourceString("Format_GuidComma"));
}
this._a = ParseNumbers.StringToInt(g.Substring(num5, length), 0x10, 0x1000);
if (!IsHexPrefix(g, (num5 + length) + 1))
{
throw new FormatException(string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Format_GuidHexPrefix"), new object[] { "{0xdddddddd, 0xdddd, etc}" }));
}
num5 = (num5 + length) + 3;
length = g.IndexOf(',', num5) - num5;
if (length <= 0)
{
throw new FormatException(Environment.GetResourceString("Format_GuidComma"));
}
this._b = (short) ParseNumbers.StringToInt(g.Substring(num5, length), 0x10, 0x1000);
if (!IsHexPrefix(g, (num5 + length) + 1))
{
throw new FormatException(string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Format_GuidHexPrefix"), new object[] { "{0xdddddddd, 0xdddd, 0xdddd, etc}" }));
}
num5 = (num5 + length) + 3;
length = g.IndexOf(',', num5) - num5;
if (length <= 0)
{
throw new FormatException(Environment.GetResourceString("Format_GuidComma"));
}
this._c = (short) ParseNumbers.StringToInt(g.Substring(num5, length), 0x10, 0x1000);
if ((g.Length <= ((num5 + length) + 1)) || (g[(num5 + length) + 1] != '{'))
{
throw new FormatException(Environment.GetResourceString("Format_GuidBrace"));
}
length++;
byte[] buffer = new byte[8];
for (int i = 0; i < 8; i++)
{
if (!IsHexPrefix(g, (num5 + length) + 1))
{
throw new FormatException(string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Format_GuidHexPrefix"), new object[] { "{... { ... 0xdd, ...}}" }));
}
num5 = (num5 + length) + 3;
if (i < 7)
{
length = g.IndexOf(',', num5) - num5;
if (length <= 0)
{
throw new FormatException(Environment.GetResourceString("Format_GuidComma"));
}
}
else
{
length = g.IndexOf('}', num5) - num5;
if (length <= 0)
{
throw new FormatException(Environment.GetResourceString("Format_GuidBraceAfterLastNumber"));
}
}
uint num8 = (uint) Convert.ToInt32(g.Substring(num5, length), 0x10);
if (num8 > 0xff)
{
throw new FormatException(Environment.GetResourceString("Overflow_Byte"));
}
buffer[i] = (byte) num8;
}
this._d = buffer[0];
this._e = buffer[1];
this._f = buffer[2];
this._g = buffer[3];
this._h = buffer[4];
this._i = buffer[5];
this._j = buffer[6];
this._k = buffer[7];
if ((((num5 + length) + 1) >= g.Length) || (g[(num5 + length) + 1] != '}'))
{
throw new FormatException(Environment.GetResourceString("Format_GuidEndBrace"));
}
if (((num5 + length) + 1) != (g.Length - 1))
{
throw new FormatException(Environment.GetResourceString("Format_ExtraJunkAtEnd"));
}
}
else
{
string s = g.Trim();
if (s.Length != 0x20)
{
throw new FormatException(Environment.GetResourceString("Format_GuidInvLen"));
}
for (int j = 0; j < s.Length; j++)
{
char c = s[j];
if ((c < '0') || (c > '9'))
{
char ch2 = char.ToUpper(c, CultureInfo.InvariantCulture);
if ((ch2 < 'A') || (ch2 > 'F'))
{
throw new FormatException(Environment.GetResourceString("Format_GuidInvalidChar"));
}
}
}
this._a = ParseNumbers.StringToInt(s.Substring(startIndex, 8), 0x10, 0x1000);
startIndex += 8;
this._b = (short) ParseNumbers.StringToInt(s.Substring(startIndex, 4), 0x10, 0x1000);
startIndex += 4;
this._c = (short) ParseNumbers.StringToInt(s.Substring(startIndex, 4), 0x10, 0x1000);
startIndex += 4;
num2 = (short) ParseNumbers.StringToInt(s.Substring(startIndex, 4), 0x10, 0x1000);
startIndex += 4;
parsePos = startIndex;
num3 = ParseNumbers.StringToLong(s, 0x10, startIndex, ref parsePos);
if ((parsePos - startIndex) != 12)
{
throw new FormatException(string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Format_GuidInvLen"), new object[0]));
}
this._d = (byte) (num2 >> 8);
this._e = (byte) num2;
num2 = (int) (num3 >> 0x20);
this._f = (byte) (num2 >> 8);
this._g = (byte) num2;
num2 = (int) num3;
this._h = (byte) (num2 >> 0x18);
this._i = (byte) (num2 >> 0x10);
this._j = (byte) (num2 >> 8);
this._k = (byte) num2;
}
}
catch (IndexOutOfRangeException)
{
throw new FormatException(Environment.GetResourceString("Format_GuidUnrecognized"));
}
}
So obviously between 3.5 and 4.5.2, the helper methods have been introduced. From there, it's supposition that the helper methods were introduced first (as instance methods, and so requiring definite assignment) and then the helper struct (GuidResult
) was introduced afterwards.
If you copy all of the 4.5.2 code into a new project, remove the line you ask about and compile, everything is still fine.
1Probably to support the introduction of Parse
/TryParse
methods on Guid
which seem to have appeared in the .NET 4.0 time frame.