/// <summary>
        /// Decodes the data from the buffer and stores the data in this object.
        /// </summary>
        /// <param name="buffer">A buffer that stores a BER encoding result.</param>
        /// <param name="length">The length of the encoding result of the data in the given buffer.</param>
        /// <returns>The number of the bytes consumed in the buffer to decode the data.</returns>
        /// <remarks>
        /// For the TLV (Tag, Length, Value) triple in the encoding result,
        /// this method provides the functionality of decoding Value.
        /// The decoding for Tag and Length will be done in Asn1Object::BerDecode method.
        /// </remarks>
        protected override int ValueBerDecode(IAsn1DecodingBuffer buffer, int length)
        {
            int consumedLen = 0;

            Asn1Tag tag     = null; //The current decoded tag.
            int     tagLen  = 0;    //The consumed length of the bytes in the buffer when decoding the current tag.
            bool    tagUsed = true;

            int curFieldIndex = 0;//The index of the field that currently is trying to decode.

            Asn1Object[] tempFields = FieldsTypeInstances;

            while (consumedLen < length)
            {
                if (curFieldIndex >= tempFields.Length)
                {
                    throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData);
                }

                if (tagUsed)
                {
                    tagLen = TagBerDecode(buffer, out tag);
                    //The decoded tag may be context , application or universal tag.
                }

                if (fieldsMetaData[curFieldIndex].Optional == false)
                {
                    //Current field is mandatory.
                    if (fieldsMetaData[curFieldIndex].AttachedTag != null)
                    {
                        //Current field has a context class tag.
                        //The decoded tag must be the context class tag of the field.
                        if (tag.Equals(fieldsMetaData[curFieldIndex].AttachedTag))
                        {
                            consumedLen += tagLen;
                            int lengthAfterCtxTag;
                            consumedLen += LengthBerDecode(buffer, out lengthAfterCtxTag);
                            //Decodes this field by Asn1Object::BerDecode when the if-else statement for fieldOptionalFlags ends.
                        }
                        else
                        {
                            throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData + " Context Tag Decode fail.");
                        }
                    }
                    else
                    {
                        //Current field doesn't have a context class tag.
                        //The decoded tag must be the application or universal class tag of the field.
                        //Retreat the buffer since the decoding of application or universal class is part of Asn1Object::BerDecode.
                        buffer.SeekBytePosition(-tagLen);
                        //Decode this field by Asn1Object::BerDecode when the if-else statement for fieldOptionalFlags ends.
                    }
                }
                else
                {
                    //Current field is optional.
                    if (fieldsMetaData[curFieldIndex].AttachedTag != null)
                    {
                        //Current field has a context class tag.
                        //Check whether it is the encoding result of this field by the context-specific class tag.
                        if (tag.Equals(fieldsMetaData[curFieldIndex].AttachedTag))
                        {
                            //Yes
                            consumedLen += tagLen;
                            int lengthAfterCtxTag;
                            consumedLen += LengthBerDecode(buffer, out lengthAfterCtxTag);
                            //Decode this field by Asn1Object::BerDecode when the if-else statement for OptionalFlags ends.
                        }
                        else
                        {
                            //No
                            tagUsed = false;
                            tempFields[curFieldIndex] = null;
                            curFieldIndex++;
                            //Check the next field.
                            continue;
                        }
                    }
                    else
                    {
                        //Current field doesn't have a context class tag.
                        //Check whether it is the encoding result of this field by the top most class tag.
                        if (tag.Equals(tempFields[curFieldIndex].TopTag))
                        {
                            //Yes
                            buffer.SeekBytePosition(-tagLen);
                            //Decode this field by Asn1Object::BerDecode when the if-else statement for OptionalFlags ends.
                        }
                        else
                        {
                            //No
                            tagUsed = false;
                            tempFields[curFieldIndex] = null;
                            curFieldIndex++;
                            //Check the next field.
                            continue;
                        }
                    }
                }
                consumedLen += tempFields[curFieldIndex].BerDecode(buffer);
                tagUsed      = true;
                curFieldIndex++;
            }

            //Ensure consumedLen equals to length.
            if (consumedLen > length)
            {
                throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData);
            }

            //Stores the decoded fields in this object.
            if (tempFields.Length != fieldsMetaData.Length)
            {
                throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData);
            }

            for (int i = 0; i < curFieldIndex; i++)
            {
                if (fieldsMetaData[i].MemberInfo.MemberType == MemberTypes.Property)
                {
                    (fieldsMetaData[i].MemberInfo as PropertyInfo).SetValue(this, tempFields[i], null);
                }
                else if (fieldsMetaData[i].MemberInfo.MemberType == MemberTypes.Field)
                {
                    (fieldsMetaData[i].MemberInfo as FieldInfo).SetValue(this, tempFields[i]);
                }
                else
                {
                    //Unreachable. Ensured by the AttributeUsage of Asn1Field.
                    throw new Asn1UserDefinedTypeInconsistent(ExceptionMessages.UserDefinedTypeInconsistent
                                                              + " Asn1Field property could only be used in properties or fields.");
                }
            }
            return(consumedLen);
        }