@ koviroli ответ на 100% правильный, поэтому, пожалуйста, примите его как ответ, как только почувствуете, что понимаете его.Я добавляю это как дополнительный ответ, потому что кажется, что вы изо всех сил пытаетесь немного понять вещи, а комментарии не дают мне возможности дать хорошее объяснение.
Быстрое объяснение конструкторов
Так как вы 'Если вы новичок в C #, я приведу краткое объяснение конструкторов.Конструктор DialogA_child
является этой частью:
public DialogA_child(string dialogId)
: base(dialogId)
{
InitialDialogId = InitialId;
WaterfallStep[] waterfallSteps = new WaterfallStep[]
{
FirstStepAsync,
SecondStepAsync,
};
AddDialog(new WaterfallDialog(InitialId, waterfallSteps));
AddDialog(new DialogA(DialogAId));
}
Каждый раз, когда вы используете new DialogA_child("xyz")
, конструктор вызывается для "конструкции" DialogA_child
.:base(dialogId)
делает так, что "xyz" отправляется конструктору базового класса DialogA_child
, который является ComponentDialog
.В конструкторе ComponentDialog
он устанавливает передаваемый аргумент (в данном случае «xyz») в значение dialogId.
Если в коде нажать ComponentDialog
и нажать F12, онприведет вас к определению ComponentDialog
, и вы увидите следующее:
public ComponentDialog(string dialogId);
.
Вот что не так
В конструкторе DialogA_child
выhave: AddDialog(new DialogA(DialogAId));
, который создает новый экземпляр DialogA
.Затем в конструкторе DialogA
у вас есть AddDialog(new DialogA_child(DialogAchildId));
, который создает другой DialogA_child
, и так далее, и так далее.
В основном DialogA
и DialogA_child
продолжают создавать новые экземпляры друг друга, вызывая StackOverflow.
Самое простое решение - просто удалить AddDialog(new DialogA(DialogAId));
.
Дополнительные примечания
Опять же, я знаю, что вы новичок в C #, поэтому я помогу вам с парой других вещей.
private const string ChoicePrompt = "choicePrompt";
, вероятно, должно бытьбыть
private const string ChoicePromptId = "choicePrompt";
, поскольку ChoicePrompt
уже определен как тип приглашения.
При определении конструкторов диалогов проще всего использовать что-то вроде:
public DialogA() : base(nameof(DialogA))
Это автоматически установит идентификатор DialogA
на "DialogA".Это поможет с двумя вещами:
Поскольку диалоги должны использовать уникальные идентификаторы, это предотвратит случайный вызов одного и того же диалога дважды.
Проще отследить, и вам не нужно указывать имя для него.Например, чтобы вызвать диалоговое окно, теперь вы можете использовать AddDialog(new DialogA());
вместо AddDialog(new DialogA(DialogAId));
.
Формирование цикла диалога
В настоящее время вы не можетеЦиклы диалогов, как вы хотите (см. обновление ниже).Вы не можете:
- Иметь
DialogA
звонить DialogA_child
- Затем
DialogA_child
снова звонить DialogA
.
Как вы виделиэто создает переполнение стека.
Вместо этого вы можете вызвать его косвенно.
Вместо того, чтобы DialogA_child
вызывать DialogA
, сделайте что-то вроде:
- Получите приглашение
DialogA_child
с опцией «Перезапустить диалог A» (или что-то уникальное). - В
OnTurnAsync
(в основном файле класса вашего бота), проверьте, ответил ли пользовательс «Перезапустить диалог A».Если это так, очистите все диалоговые окна (или просто замените) и затем начните DialogA
снова.
Код:
DialogA_child
:
private static async Task<DialogTurnResult> FirstStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
{
return await stepContext.PromptAsync(
choicePrompt,
new PromptOptions
{
Prompt = MessageFactory.Text($"Here are your choices:"),
Choices = new List<Choice> { new Choice { Value = "Restart Dialog A" }, new Choice { Value = "Open Dialog B" }, },
RetryPrompt = MessageFactory.Text($"Please choose one of the options."),
});
}
<myBot>.cs
:
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
var activity = turnContext.Activity;
var dc = await Dialogs.CreateContextAsync(turnContext);
if (activity.Text == "Restart Dialog A")
{
await dc.CancelAllDialogsAsync();
await dc.BeginDialogAsync(nameof(DialogA));
}
Обновление
BotBuilder SDK V4.3 скоро выйдет, что позволяет любому дочернему или дочернему диалогу вызывать любой диалог, определенный родителем.См. этот запрос на извлечение .Я верю вы можете сделать так, чтобы дочерний диалог вызывал родителя, как запросил OP, но он все еще новый, и я не проверял.