嗨,我正在尝试使用 a内部ScriptBlock
的特定来执行 a ,但是如果其中有一个管道,它将永远挂起(可能是死锁)。SessionState
ICommandPredictor
ScriptBlock
我有一个在这里重现问题的项目。
要重新创建问题:
- 克隆仓库
- 在 Visual Studio 2021 中打开
Predictor.cs
在第 23 行设置断点- 从调试开始
- 在打开的终端中输入一个字符。
- Visual Studio 应弹出断点命中
- 按 F10(跳过)
- 因为我们被困住了,你永远不会到达第 28或31行。
所以我在执行 ScriptBlocks 的方式上可能做错了什么。但流程是:
- 当终端启动时,它会执行Install-ScriptBlock
- 这
ScriptBlock
使用一个新的 Session 执行 a ,该 Session 又执行set-scriptblock,set-scriptblock
存储提供ScriptBlock
的和新的SessionState
。 - 创建一个 ICommandPredictor 并将其注册到子系统。
- 这
- 当您在终端中键入
ICommandPredictor
被调用时,这反过来会尝试执行set-scriptblock
使用同一会话保存的脚本块。
我希望这是有道理的,并且我知道流程有些复杂,但是我无法在不破坏我的用例的情况下删除流程中的任何步骤..
那么有什么方法可以改变它以允许我在执行 aScriptBlock
时ICommandPredictor
执行SessionState
aScriptBlock
而不导致它挂起?
万一我的链接中断了,它有以下代码:
[Cmdlet("Install", "ScriptBlock"), OutputType(typeof(bool))]
public class InstallScriptBlock : PSCmdlet
{
public static string AssemblyPath
{
get
{
string codeBase = Assembly.GetExecutingAssembly().Location;
UriBuilder uri = new UriBuilder(codeBase);
return Uri.UnescapeDataString(uri.Path); ;
}
}
protected override void ProcessRecord()
{
var path = Path.Combine(Path.GetDirectoryName(AssemblyPath), "script.ps1");
var script = ScriptBlock.Create("set-scriptblock -Expression { @( 'One', ' *$Two' ) | % { $_.trim(\" *$\") } }");
InvokeCommand.InvokeScript(true, script, new List<object>());
InvokeCommand.InvokeScript("Set-PSReadLineOption -PredictionSource Plugin");
SubsystemManager.RegisterSubsystem<ICommandPredictor, Predictor>(new Predictor());
base.ProcessRecord();
}
}
public class Predictor : ICommandPredictor
{
public string Description => "TestHang";
public Guid Id => new Guid("7959E3B3-8444-478A-A821-48A07FB407DF");
public string Name => "TestHang";
public bool CanAcceptFeedback(PredictionClient client, PredictorFeedbackKind feedback)
{
return false;
}
public SuggestionPackage GetSuggestion(PredictionClient client, PredictionContext context, CancellationToken cancellationToken)
{
try
{
//The line below will cause a permanent hang of this thread!
var result = State.InvokeCommand.InvokeScript(State.SessionState, State.ScriptBlock);
//We never get here!
}
catch (Exception ex)
{
throw;
}
return default;
}
public void OnCommandLineAccepted(PredictionClient client, IReadOnlyList<string> history)
{
}
public void OnCommandLineExecuted(PredictionClient client, string commandLine, bool success)
{
}
public void OnSuggestionAccepted(PredictionClient client, uint session, string acceptedSuggestion)
{
}
public void OnSuggestionDisplayed(PredictionClient client, uint session, int countOrIndex)
{
}
}
[Cmdlet("Set", "ScriptBlock"), OutputType(typeof(bool))]
public class SetScriptBlock : PSCmdlet
{
/// <summary>
/// <para type="description">Indicates whether the user would like to receive output. </para>
/// </summary>
[Parameter(Mandatory = true)]
public ScriptBlock Expression { get; set; } = null!;
protected override void ProcessRecord()
{
State.ScriptBlock = Expression;
State.SessionState = SessionState;
State.InvokeCommand = InvokeCommand;
base.ProcessRecord();
}
}
static class State
{
public static CommandInvocationIntrinsics InvokeCommand { get; set; }
public static SessionState SessionState { get; set; }
public static ScriptBlock ScriptBlock { get; set; }
}