public override ISharedMessageChainBuilder Add(ISharedChatMessage message)
 {
     if (_builtMessages != null)
     {
         throw new InvalidOperationException("由于之前进行过构建操作, 无法添加新的消息实例");
     }
     return(base.Add(message));
 }
 public override ISharedMessageChainBuilder Add(ISharedChatMessage message)
 {
     if (message is not IChatMessage)
     {
         throw new InvalidOperationException($"添加的消息实例 {message.GetType().FullName} 不实现 {typeof(IChatMessage).FullName}");
     }
     return(base.Add(message));
 }
        private async Task <int> CommonSendMessageAsync(string action, long?qqNumber, long?groupNumber, ISharedChatMessage[] chain, int?quoteMsgId, CancellationToken token = default)
        {
            InternalSessionInfo session = SafeGetSession();

            if (chain == null || chain.Length == 0)
            {
                throw new ArgumentException("消息链必须为非空且至少有1条消息。");
            }
            int emptyPlainCount = 0;

            for (int i = 0; i < chain.Length; i++)
            {
                ISharedChatMessage msg = chain[i];
                if (msg is not IChatMessage)
                {
                    throw new ArgumentException($"不允许发送未实现 {typeof(IChatMessage).FullName} 接口的消息。");
                }
                if (msg is ISourceMessage)
                {
                    throw new ArgumentException("无法发送基本信息(SourceMessage)。");
                }
                if (msg is IQuoteMessage)
                {
                    throw new ArgumentException("无法发送引用信息(QuoteMessage), 请使用quoteMsgId参数进行引用。");
                }
                if (msg is IPlainMessage pm && string.IsNullOrEmpty(pm.Message))
                {
                    emptyPlainCount++;
                }
            }
            if (emptyPlainCount == chain.Length)
            {
                throw new ArgumentException("消息链仅含文本消息且所有文本均为空。");
            }
            // 前边已经检查了所有元素均实现了 IChatMessage 接口, 但直接强制转换数组类型会引发 InvalidCastException, 所以玩一点 trick
            IEnumerable <IChatMessage> convertedChain = Unsafe.As <ISharedChatMessage[], IEnumerable <IChatMessage> >(ref chain);

            CreateLinkedUserSessionToken(session.Token, token, out CancellationTokenSource? cts, out token);
            var payload = new
            {
                sessionKey   = session.SessionKey,
                qq           = qqNumber,
                group        = groupNumber,
                quote        = quoteMsgId,
                messageChain = convertedChain
            };

            using JsonDocument j = await _client.PostAsJsonAsync($"{_options.BaseUrl}/{action}", payload, _chatMessageSerializingOptions, token).GetJsonAsync(token).DisposeWhenCompleted(cts).ConfigureAwait(false);

            JsonElement root = j.RootElement;

            root.EnsureApiRespCode();
            return(root.GetProperty("messageId").GetInt32());
        }