public static async ValueTask <RfcLdapMessage> Decode(IAsn1Decoder dec, Stream inRenamed, int len, CancellationToken cancellationToken)
        {
            var message = new RfcLdapMessage(await DecodeStructured(dec, inRenamed, len, cancellationToken).ConfigureAwait(false));

            // Decode implicitly tagged protocol operation from an Asn1Tagged type
            // to its appropriate application type.
            var protocolOp   = (Asn1Tagged)message.get_Renamed(1);
            var protocolOpId = protocolOp.GetIdentifier();
            var content      = ((Asn1OctetString)protocolOp.TaggedValue).ByteValue();
            var bais         = new MemoryStream(content);

            switch (protocolOpId.Tag)
            {
            case LdapMessage.SearchResponse:
                message.set_Renamed(1, new RfcSearchResultEntry(await DecodeStructured(dec, bais, content.Length, cancellationToken).ConfigureAwait(false)));
                break;

            case LdapMessage.SearchResult:
                message.set_Renamed(1, await RfcLdapResult.Decode(dec, bais, content.Length, cancellationToken, newContent => new RfcSearchResultDone(newContent)).ConfigureAwait(false));
                break;

            case LdapMessage.SearchResultReference:
                message.set_Renamed(1, new RfcSearchResultReference(await DecodeStructured(dec, bais, content.Length, cancellationToken).ConfigureAwait(false)));
                break;

            case LdapMessage.AddResponse:
                message.set_Renamed(1, await RfcLdapResult.Decode(dec, bais, content.Length, cancellationToken, newContent => new RfcAddResponse(newContent)).ConfigureAwait(false));
                break;

            case LdapMessage.BindResponse:
                message.set_Renamed(1, await RfcBindResponse.Decode(dec, bais, content.Length, cancellationToken).ConfigureAwait(false));
                break;

            case LdapMessage.CompareResponse:
                message.set_Renamed(1, await RfcLdapResult.Decode(dec, bais, content.Length, cancellationToken, newContent => new RfcCompareResponse(newContent)).ConfigureAwait(false));
                break;

            case LdapMessage.DelResponse:
                message.set_Renamed(1, await RfcLdapResult.Decode(dec, bais, content.Length, cancellationToken, newContent => new RfcDelResponse(newContent)).ConfigureAwait(false));
                break;

            case LdapMessage.ExtendedResponse:
                message.set_Renamed(1, new RfcExtendedResponse(await DecodeStructured(dec, bais, content.Length, cancellationToken).ConfigureAwait(false)));
                break;

            case LdapMessage.IntermediateResponse:
                message.set_Renamed(1, new RfcIntermediateResponse(await DecodeStructured(dec, bais, content.Length, cancellationToken).ConfigureAwait(false)));
                break;

            case LdapMessage.ModifyResponse:
                message.set_Renamed(1, await RfcLdapResult.Decode(dec, bais, content.Length, cancellationToken, newContent => new RfcModifyResponse(newContent)).ConfigureAwait(false));
                break;

            case LdapMessage.ModifyRdnResponse:
                message.set_Renamed(1, await RfcLdapResult.Decode(dec, bais, content.Length, cancellationToken, newContent => new RfcModifyDnResponse(newContent)).ConfigureAwait(false));
                break;

            default:
                throw new Exception("RfcLdapMessage: Invalid tag: " + protocolOpId.Tag);
            }

            // decode optional implicitly tagged controls from Asn1Tagged type to
            // to RFC 2251 types.
            if (message.Size() > 2)
            {
                var controls = (Asn1Tagged)message.get_Renamed(2);

                // Asn1Identifier controlsId = protocolOp.getIdentifier();
                // we could check to make sure we have controls here....
                content = ((Asn1OctetString)controls.TaggedValue).ByteValue();
                bais    = new MemoryStream(content);
                message.set_Renamed(2, await RfcControls.Decode(dec, bais, content.Length, cancellationToken).ConfigureAwait(false));
            }

            return(message);
        }