/// <summary>
        /// Look up and cross-link all field types etc.
        /// </summary>
        internal void CrossLink()
        {
            if (Proto.HasExtendee)
            {
                IDescriptor extendee = File.DescriptorPool.LookupSymbol(Proto.Extendee, this);
                if (!(extendee is MessageDescriptor))
                {
                    throw new DescriptorValidationException(this, "\"" + Proto.Extendee + "\" is not a message type.");
                }
                containingType = (MessageDescriptor)extendee;

                if (!containingType.IsExtensionNumber(FieldNumber))
                {
                    throw new DescriptorValidationException(this,
                                                            "\"" + containingType.FullName + "\" does not declare " +
                                                            FieldNumber + " as an extension number.");
                }
            }

            if (Proto.HasTypeName)
            {
                IDescriptor typeDescriptor =
                    File.DescriptorPool.LookupSymbol(Proto.TypeName, this);

                if (!Proto.HasType)
                {
                    // Choose field type based on symbol.
                    if (typeDescriptor is MessageDescriptor)
                    {
                        fieldType  = FieldType.Message;
                        mappedType = MappedType.Message;
                    }
                    else if (typeDescriptor is EnumDescriptor)
                    {
                        fieldType  = FieldType.Enum;
                        mappedType = MappedType.Enum;
                    }
                    else
                    {
                        throw new DescriptorValidationException(this, "\"" + Proto.TypeName + "\" is not a type.");
                    }
                }

                if (MappedType == MappedType.Message)
                {
                    if (!(typeDescriptor is MessageDescriptor))
                    {
                        throw new DescriptorValidationException(this,
                                                                "\"" + Proto.TypeName + "\" is not a message type.");
                    }
                    messageType = (MessageDescriptor)typeDescriptor;

                    if (Proto.HasDefaultValue)
                    {
                        throw new DescriptorValidationException(this, "Messages can't have default values.");
                    }
                }
                else if (MappedType == Descriptors.MappedType.Enum)
                {
                    if (!(typeDescriptor is EnumDescriptor))
                    {
                        throw new DescriptorValidationException(this, "\"" + Proto.TypeName + "\" is not an enum type.");
                    }
                    enumType = (EnumDescriptor)typeDescriptor;
                }
                else
                {
                    throw new DescriptorValidationException(this, "Field with primitive type has type_name.");
                }
            }
            else
            {
                if (MappedType == MappedType.Message || MappedType == MappedType.Enum)
                {
                    throw new DescriptorValidationException(this, "Field with message or enum type missing type_name.");
                }
            }

            // We don't attempt to parse the default value until here because for
            // enums we need the enum type's descriptor.
            if (Proto.HasDefaultValue)
            {
                if (IsRepeated)
                {
                    throw new DescriptorValidationException(this, "Repeated fields cannot have default values.");
                }

                try
                {
                    switch (FieldType)
                    {
                    case FieldType.Int32:
                    case FieldType.SInt32:
                    case FieldType.SFixed32:
                        defaultValue = TextFormat.ParseInt32(Proto.DefaultValue);
                        break;

                    case FieldType.UInt32:
                    case FieldType.Fixed32:
                        defaultValue = TextFormat.ParseUInt32(Proto.DefaultValue);
                        break;

                    case FieldType.Int64:
                    case FieldType.SInt64:
                    case FieldType.SFixed64:
                        defaultValue = TextFormat.ParseInt64(Proto.DefaultValue);
                        break;

                    case FieldType.UInt64:
                    case FieldType.Fixed64:
                        defaultValue = TextFormat.ParseUInt64(Proto.DefaultValue);
                        break;

                    case FieldType.Float:
                        defaultValue = TextFormat.ParseFloat(Proto.DefaultValue);
                        break;

                    case FieldType.Double:
                        defaultValue = TextFormat.ParseDouble(Proto.DefaultValue);
                        break;

                    case FieldType.Bool:
                        if (Proto.DefaultValue == "true")
                        {
                            defaultValue = true;
                        }
                        else if (Proto.DefaultValue == "false")
                        {
                            defaultValue = false;
                        }
                        else
                        {
                            throw new FormatException("Boolean values must be \"true\" or \"false\"");
                        }
                        break;

                    case FieldType.String:
                        defaultValue = Proto.DefaultValue;
                        break;

                    case FieldType.Bytes:
                        try
                        {
                            defaultValue = TextFormat.UnescapeBytes(Proto.DefaultValue);
                        }
                        catch (FormatException e)
                        {
                            throw new DescriptorValidationException(this,
                                                                    "Couldn't parse default value: " + e.Message);
                        }
                        break;

                    case FieldType.Enum:
                        defaultValue = enumType.FindValueByName(Proto.DefaultValue);
                        if (defaultValue == null)
                        {
                            throw new DescriptorValidationException(this,
                                                                    "Unknown enum default value: \"" +
                                                                    Proto.DefaultValue + "\"");
                        }
                        break;

                    case FieldType.Message:
                    case FieldType.Group:
                        throw new DescriptorValidationException(this, "Message type had default value.");
                    }
                }
                catch (FormatException e)
                {
                    DescriptorValidationException validationException =
                        new DescriptorValidationException(this,
                                                          "Could not parse default value: \"" + Proto.DefaultValue +
                                                          "\"", e);
                    throw validationException;
                }
            }
            else
            {
                // Determine the default default for this field.
                if (IsRepeated)
                {
                    defaultValue = Lists <object> .Empty;
                }
                else
                {
                    switch (MappedType)
                    {
                    case MappedType.Enum:
                        // We guarantee elsewhere that an enum type always has at least
                        // one possible value.
                        defaultValue = enumType.Values[0];
                        break;

                    case MappedType.Message:
                        defaultValue = null;
                        break;

                    default:
                        defaultValue = GetDefaultValueForMappedType(MappedType);
                        break;
                    }
                }
            }

            if (!IsExtension)
            {
                File.DescriptorPool.AddFieldByNumber(this);
            }

            if (containingType != null && containingType.Options.MessageSetWireFormat)
            {
                if (IsExtension)
                {
                    if (!IsOptional || FieldType != FieldType.Message)
                    {
                        throw new DescriptorValidationException(this,
                                                                "Extensions of MessageSets must be optional messages.");
                    }
                }
                else
                {
                    throw new DescriptorValidationException(this, "MessageSets cannot have fields, only extensions.");
                }
            }
        }